0001 """Regresssion tests for urllib""" 0002 0003 import urllib 0004 import httplib 0005 import unittest 0006 from test import test_support 0007 import os 0008 import mimetools 0009 import StringIO 0010 0011 def hexescape(char): 0012 """Escape char as RFC 2396 specifies""" 0013 hex_repr = hex(ord(char))[2:].upper() 0014 if len(hex_repr) == 1: 0015 hex_repr = "0%s" % hex_repr 0016 return "%" + hex_repr 0017 0018 class urlopen_FileTests(unittest.TestCase): 0019 """Test urlopen() opening a temporary file. 0020 0021 Try to test as much functionality as possible so as to cut down on reliance 0022 on connecting to the Net for testing. 0023 0024 """ 0025 0026 def setUp(self): 0027 """Setup of a temp file to use for testing""" 0028 self.text = "test_urllib: %s\n" % self.__class__.__name__ 0029 FILE = file(test_support.TESTFN, 'wb') 0030 try: 0031 FILE.write(self.text) 0032 finally: 0033 FILE.close() 0034 self.pathname = test_support.TESTFN 0035 self.returned_obj = urllib.urlopen("file:%s" % self.pathname) 0036 0037 def tearDown(self): 0038 """Shut down the open object""" 0039 self.returned_obj.close() 0040 os.remove(test_support.TESTFN) 0041 0042 def test_interface(self): 0043 # Make sure object returned by urlopen() has the specified methods 0044 for attr in ("read", "readline", "readlines", "fileno", 0045 "close", "info", "geturl", "__iter__"): 0046 self.assert_(hasattr(self.returned_obj, attr), 0047 "object returned by urlopen() lacks %s attribute" % 0048 attr) 0049 0050 def test_read(self): 0051 self.assertEqual(self.text, self.returned_obj.read()) 0052 0053 def test_readline(self): 0054 self.assertEqual(self.text, self.returned_obj.readline()) 0055 self.assertEqual('', self.returned_obj.readline(), 0056 "calling readline() after exhausting the file did not" 0057 " return an empty string") 0058 0059 def test_readlines(self): 0060 lines_list = self.returned_obj.readlines() 0061 self.assertEqual(len(lines_list), 1, 0062 "readlines() returned the wrong number of lines") 0063 self.assertEqual(lines_list[0], self.text, 0064 "readlines() returned improper text") 0065 0066 def test_fileno(self): 0067 file_num = self.returned_obj.fileno() 0068 self.assert_(isinstance(file_num, int), 0069 "fileno() did not return an int") 0070 self.assertEqual(os.read(file_num, len(self.text)), self.text, 0071 "Reading on the file descriptor returned by fileno() " 0072 "did not return the expected text") 0073 0074 def test_close(self): 0075 # Test close() by calling it hear and then having it be called again 0076 # by the tearDown() method for the test 0077 self.returned_obj.close() 0078 0079 def test_info(self): 0080 self.assert_(isinstance(self.returned_obj.info(), mimetools.Message)) 0081 0082 def test_geturl(self): 0083 self.assertEqual(self.returned_obj.geturl(), self.pathname) 0084 0085 def test_iter(self): 0086 # Test iterator 0087 # Don't need to count number of iterations since test would fail the 0088 # instant it returned anything beyond the first line from the 0089 # comparison 0090 for line in self.returned_obj.__iter__(): 0091 self.assertEqual(line, self.text) 0092 0093 class urlopen_HttpTests(unittest.TestCase): 0094 """Test urlopen() opening a fake http connection.""" 0095 0096 def fakehttp(self, fakedata): 0097 class FakeSocket(StringIO.StringIO): 0098 def sendall(self, str): pass 0099 def makefile(self, mode, name): return self 0100 def read(self, amt=None): 0101 if self.closed: return '' 0102 return StringIO.StringIO.read(self, amt) 0103 def readline(self, length=None): 0104 if self.closed: return '' 0105 return StringIO.StringIO.readline(self, length) 0106 class FakeHTTPConnection(httplib.HTTPConnection): 0107 def connect(self): 0108 self.sock = FakeSocket(fakedata) 0109 assert httplib.HTTP._connection_class == httplib.HTTPConnection 0110 httplib.HTTP._connection_class = FakeHTTPConnection 0111 0112 def unfakehttp(self): 0113 httplib.HTTP._connection_class = httplib.HTTPConnection 0114 0115 def test_read(self): 0116 self.fakehttp('Hello!') 0117 try: 0118 fp = urllib.urlopen("http://python.org/") 0119 self.assertEqual(fp.readline(), 'Hello!') 0120 self.assertEqual(fp.readline(), '') 0121 finally: 0122 self.unfakehttp() 0123 0124 class urlretrieve_FileTests(unittest.TestCase): 0125 """Test urllib.urlretrieve() on local files""" 0126 0127 def setUp(self): 0128 # Create a temporary file. 0129 self.text = 'testing urllib.urlretrieve' 0130 FILE = file(test_support.TESTFN, 'wb') 0131 FILE.write(self.text) 0132 FILE.close() 0133 0134 def tearDown(self): 0135 # Delete the temporary file. 0136 os.remove(test_support.TESTFN) 0137 0138 def test_basic(self): 0139 # Make sure that a local file just gets its own location returned and 0140 # a headers value is returned. 0141 result = urllib.urlretrieve("file:%s" % test_support.TESTFN) 0142 self.assertEqual(result[0], test_support.TESTFN) 0143 self.assert_(isinstance(result[1], mimetools.Message), 0144 "did not get a mimetools.Message instance as second " 0145 "returned value") 0146 0147 def test_copy(self): 0148 # Test that setting the filename argument works. 0149 second_temp = "%s.2" % test_support.TESTFN 0150 result = urllib.urlretrieve("file:%s" % test_support.TESTFN, second_temp) 0151 self.assertEqual(second_temp, result[0]) 0152 self.assert_(os.path.exists(second_temp), "copy of the file was not " 0153 "made") 0154 FILE = file(second_temp, 'rb') 0155 try: 0156 text = FILE.read() 0157 finally: 0158 FILE.close() 0159 self.assertEqual(self.text, text) 0160 0161 def test_reporthook(self): 0162 # Make sure that the reporthook works. 0163 def hooktester(count, block_size, total_size, count_holder=[0]): 0164 self.assert_(isinstance(count, int)) 0165 self.assert_(isinstance(block_size, int)) 0166 self.assert_(isinstance(total_size, int)) 0167 self.assertEqual(count, count_holder[0]) 0168 count_holder[0] = count_holder[0] + 1 0169 second_temp = "%s.2" % test_support.TESTFN 0170 urllib.urlretrieve(test_support.TESTFN, second_temp, hooktester) 0171 os.remove(second_temp) 0172 0173 class QuotingTests(unittest.TestCase): 0174 """Tests for urllib.quote() and urllib.quote_plus() 0175 0176 According to RFC 2396 ("Uniform Resource Identifiers), to escape a 0177 character you write it as '%' + <2 character US-ASCII hex value>. The Python 0178 code of ``'%' + hex(ord(<character>))[2:]`` escapes a character properly. 0179 Case does not matter on the hex letters. 0180 0181 The various character sets specified are: 0182 0183 Reserved characters : ";/?:@&=+$," 0184 Have special meaning in URIs and must be escaped if not being used for 0185 their special meaning 0186 Data characters : letters, digits, and "-_.!~*'()" 0187 Unreserved and do not need to be escaped; can be, though, if desired 0188 Control characters : 0x00 - 0x1F, 0x7F 0189 Have no use in URIs so must be escaped 0190 space : 0x20 0191 Must be escaped 0192 Delimiters : '<>#%"' 0193 Must be escaped 0194 Unwise : "{}|\^[]`" 0195 Must be escaped 0196 0197 """ 0198 0199 def test_never_quote(self): 0200 # Make sure quote() does not quote letters, digits, and "_,.-" 0201 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0202 "abcdefghijklmnopqrstuvwxyz", 0203 "0123456789", 0204 "_.-"]) 0205 result = urllib.quote(do_not_quote) 0206 self.assertEqual(do_not_quote, result, 0207 "using quote(): %s != %s" % (do_not_quote, result)) 0208 result = urllib.quote_plus(do_not_quote) 0209 self.assertEqual(do_not_quote, result, 0210 "using quote_plus(): %s != %s" % (do_not_quote, result)) 0211 0212 def test_default_safe(self): 0213 # Test '/' is default value for 'safe' parameter 0214 self.assertEqual(urllib.quote.func_defaults[0], '/') 0215 0216 def test_safe(self): 0217 # Test setting 'safe' parameter does what it should do 0218 quote_by_default = "<>" 0219 result = urllib.quote(quote_by_default, safe=quote_by_default) 0220 self.assertEqual(quote_by_default, result, 0221 "using quote(): %s != %s" % (quote_by_default, result)) 0222 result = urllib.quote_plus(quote_by_default, safe=quote_by_default) 0223 self.assertEqual(quote_by_default, result, 0224 "using quote_plus(): %s != %s" % 0225 (quote_by_default, result)) 0226 0227 def test_default_quoting(self): 0228 # Make sure all characters that should be quoted are by default sans 0229 # space (separate test for that). 0230 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F 0231 should_quote.append('<>#%"{}|\^[]`') 0232 should_quote.append(chr(127)) # For 0x7F 0233 should_quote = ''.join(should_quote) 0234 for char in should_quote: 0235 result = urllib.quote(char) 0236 self.assertEqual(hexescape(char), result, 0237 "using quote(): %s should be escaped to %s, not %s" % 0238 (char, hexescape(char), result)) 0239 result = urllib.quote_plus(char) 0240 self.assertEqual(hexescape(char), result, 0241 "using quote_plus(): " 0242 "%s should be escapes to %s, not %s" % 0243 (char, hexescape(char), result)) 0244 del should_quote 0245 partial_quote = "ab[]cd" 0246 expected = "ab%5B%5Dcd" 0247 result = urllib.quote(partial_quote) 0248 self.assertEqual(expected, result, 0249 "using quote(): %s != %s" % (expected, result)) 0250 self.assertEqual(expected, result, 0251 "using quote_plus(): %s != %s" % (expected, result)) 0252 0253 def test_quoting_space(self): 0254 # Make sure quote() and quote_plus() handle spaces as specified in 0255 # their unique way 0256 result = urllib.quote(' ') 0257 self.assertEqual(result, hexescape(' '), 0258 "using quote(): %s != %s" % (result, hexescape(' '))) 0259 result = urllib.quote_plus(' ') 0260 self.assertEqual(result, '+', 0261 "using quote_plus(): %s != +" % result) 0262 given = "a b cd e f" 0263 expect = given.replace(' ', hexescape(' ')) 0264 result = urllib.quote(given) 0265 self.assertEqual(expect, result, 0266 "using quote(): %s != %s" % (expect, result)) 0267 expect = given.replace(' ', '+') 0268 result = urllib.quote_plus(given) 0269 self.assertEqual(expect, result, 0270 "using quote_plus(): %s != %s" % (expect, result)) 0271 0272 class UnquotingTests(unittest.TestCase): 0273 """Tests for unquote() and unquote_plus() 0274 0275 See the doc string for quoting_Tests for details on quoting and such. 0276 0277 """ 0278 0279 def test_unquoting(self): 0280 # Make sure unquoting of all ASCII values works 0281 escape_list = [] 0282 for num in range(128): 0283 given = hexescape(chr(num)) 0284 expect = chr(num) 0285 result = urllib.unquote(given) 0286 self.assertEqual(expect, result, 0287 "using unquote(): %s != %s" % (expect, result)) 0288 result = urllib.unquote_plus(given) 0289 self.assertEqual(expect, result, 0290 "using unquote_plus(): %s != %s" % 0291 (expect, result)) 0292 escape_list.append(given) 0293 escape_string = ''.join(escape_list) 0294 del escape_list 0295 result = urllib.unquote(escape_string) 0296 self.assertEqual(result.count('%'), 1, 0297 "using quote(): not all characters escaped; %s" % 0298 result) 0299 result = urllib.unquote(escape_string) 0300 self.assertEqual(result.count('%'), 1, 0301 "using unquote(): not all characters escaped: " 0302 "%s" % result) 0303 0304 def test_unquoting_parts(self): 0305 # Make sure unquoting works when have non-quoted characters 0306 # interspersed 0307 given = 'ab%sd' % hexescape('c') 0308 expect = "abcd" 0309 result = urllib.unquote(given) 0310 self.assertEqual(expect, result, 0311 "using quote(): %s != %s" % (expect, result)) 0312 result = urllib.unquote_plus(given) 0313 self.assertEqual(expect, result, 0314 "using unquote_plus(): %s != %s" % (expect, result)) 0315 0316 def test_unquoting_plus(self): 0317 # Test difference between unquote() and unquote_plus() 0318 given = "are+there+spaces..." 0319 expect = given 0320 result = urllib.unquote(given) 0321 self.assertEqual(expect, result, 0322 "using unquote(): %s != %s" % (expect, result)) 0323 expect = given.replace('+', ' ') 0324 result = urllib.unquote_plus(given) 0325 self.assertEqual(expect, result, 0326 "using unquote_plus(): %s != %s" % (expect, result)) 0327 0328 class urlencode_Tests(unittest.TestCase): 0329 """Tests for urlencode()""" 0330 0331 def help_inputtype(self, given, test_type): 0332 """Helper method for testing different input types. 0333 0334 'given' must lead to only the pairs: 0335 * 1st, 1 0336 * 2nd, 2 0337 * 3rd, 3 0338 0339 Test cannot assume anything about order. Docs make no guarantee and 0340 have possible dictionary input. 0341 0342 """ 0343 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"] 0344 result = urllib.urlencode(given) 0345 for expected in expect_somewhere: 0346 self.assert_(expected in result, 0347 "testing %s: %s not found in %s" % 0348 (test_type, expected, result)) 0349 self.assertEqual(result.count('&'), 2, 0350 "testing %s: expected 2 '&'s; got %s" % 0351 (test_type, result.count('&'))) 0352 amp_location = result.index('&') 0353 on_amp_left = result[amp_location - 1] 0354 on_amp_right = result[amp_location + 1] 0355 self.assert_(on_amp_left.isdigit() and on_amp_right.isdigit(), 0356 "testing %s: '&' not located in proper place in %s" % 0357 (test_type, result)) 0358 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps 0359 "testing %s: " 0360 "unexpected number of characters: %s != %s" % 0361 (test_type, len(result), (5 * 3) + 2)) 0362 0363 def test_using_mapping(self): 0364 # Test passing in a mapping object as an argument. 0365 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'}, 0366 "using dict as input type") 0367 0368 def test_using_sequence(self): 0369 # Test passing in a sequence of two-item sequences as an argument. 0370 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')], 0371 "using sequence of two-item tuples as input") 0372 0373 def test_quoting(self): 0374 # Make sure keys and values are quoted using quote_plus() 0375 given = {"&":"="} 0376 expect = "%s=%s" % (hexescape('&'), hexescape('=')) 0377 result = urllib.urlencode(given) 0378 self.assertEqual(expect, result) 0379 given = {"key name":"A bunch of pluses"} 0380 expect = "key+name=A+bunch+of+pluses" 0381 result = urllib.urlencode(given) 0382 self.assertEqual(expect, result) 0383 0384 def test_doseq(self): 0385 # Test that passing True for 'doseq' parameter works correctly 0386 given = {'sequence':['1', '2', '3']} 0387 expect = "sequence=%s" % urllib.quote_plus(str(['1', '2', '3'])) 0388 result = urllib.urlencode(given) 0389 self.assertEqual(expect, result) 0390 result = urllib.urlencode(given, True) 0391 for value in given["sequence"]: 0392 expect = "sequence=%s" % value 0393 self.assert_(expect in result, 0394 "%s not found in %s" % (expect, result)) 0395 self.assertEqual(result.count('&'), 2, 0396 "Expected 2 '&'s, got %s" % result.count('&')) 0397 0398 class Pathname_Tests(unittest.TestCase): 0399 """Test pathname2url() and url2pathname()""" 0400 0401 def test_basic(self): 0402 # Make sure simple tests pass 0403 expected_path = os.path.join("parts", "of", "a", "path") 0404 expected_url = "parts/of/a/path" 0405 result = urllib.pathname2url(expected_path) 0406 self.assertEqual(expected_url, result, 0407 "pathname2url() failed; %s != %s" % 0408 (result, expected_url)) 0409 result = urllib.url2pathname(expected_url) 0410 self.assertEqual(expected_path, result, 0411 "url2pathame() failed; %s != %s" % 0412 (result, expected_path)) 0413 0414 def test_quoting(self): 0415 # Test automatic quoting and unquoting works for pathnam2url() and 0416 # url2pathname() respectively 0417 given = os.path.join("needs", "quot=ing", "here") 0418 expect = "needs/%s/here" % urllib.quote("quot=ing") 0419 result = urllib.pathname2url(given) 0420 self.assertEqual(expect, result, 0421 "pathname2url() failed; %s != %s" % 0422 (expect, result)) 0423 expect = given 0424 result = urllib.url2pathname(result) 0425 self.assertEqual(expect, result, 0426 "url2pathname() failed; %s != %s" % 0427 (expect, result)) 0428 given = os.path.join("make sure", "using_quote") 0429 expect = "%s/using_quote" % urllib.quote("make sure") 0430 result = urllib.pathname2url(given) 0431 self.assertEqual(expect, result, 0432 "pathname2url() failed; %s != %s" % 0433 (expect, result)) 0434 given = "make+sure/using_unquote" 0435 expect = os.path.join("make+sure", "using_unquote") 0436 result = urllib.url2pathname(given) 0437 self.assertEqual(expect, result, 0438 "url2pathname() failed; %s != %s" % 0439 (expect, result)) 0440 0441 0442 0443 def test_main(): 0444 test_support.run_unittest( 0445 urlopen_FileTests, 0446 urlopen_HttpTests, 0447 urlretrieve_FileTests, 0448 QuotingTests, 0449 UnquotingTests, 0450 urlencode_Tests, 0451 Pathname_Tests 0452 ) 0453 0454 0455 0456 if __name__ == '__main__': 0457 test_main() 0458
Generated by PyXR 0.9.4