blob: 4e1a845aa4fb68d4d421acccc8c4e1627a10f120 [file] [log] [blame]
Just van Rossum52e14d62002-12-30 22:08:05 +00001import sys
2import os
3import marshal
4import imp
5import struct
6import time
Neal Norwitzb155b622006-01-23 07:52:13 +00007import unittest
Just van Rossum52e14d62002-12-30 22:08:05 +00008
9import zlib # implied prerequisite
10from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED
11from test import test_support
12from test.test_importhooks import ImportHooksBaseTestCase, test_src, test_co
13
14import zipimport
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000015import linecache
16import doctest
17import inspect
18import StringIO
19from traceback import extract_tb, extract_stack, print_tb
20raise_src = 'def do_raise(): raise TypeError\n'
Just van Rossum52e14d62002-12-30 22:08:05 +000021
Neal Norwitzb155b622006-01-23 07:52:13 +000022# so we only run testAFakeZlib once if this test is run repeatedly
23# which happens when we look for ref leaks
24test_imported = False
25
26
Just van Rossum52e14d62002-12-30 22:08:05 +000027def make_pyc(co, mtime):
28 data = marshal.dumps(co)
Jack Jansen472e7db2003-01-08 16:37:03 +000029 if type(mtime) is type(0.0):
Tim Petersf2715e02003-02-19 02:35:07 +000030 # Mac mtimes need a bit of special casing
31 if mtime < 0x7fffffff:
32 mtime = int(mtime)
33 else:
34 mtime = int(-0x100000000L + long(mtime))
Jack Jansen472e7db2003-01-08 16:37:03 +000035 pyc = imp.get_magic() + struct.pack("<i", int(mtime)) + data
Just van Rossum52e14d62002-12-30 22:08:05 +000036 return pyc
37
Tim Peters68f2d002006-01-23 22:19:24 +000038def module_path_to_dotted_name(path):
39 return path.replace(os.sep, '.')
40
Just van Rossum52e14d62002-12-30 22:08:05 +000041NOW = time.time()
42test_pyc = make_pyc(test_co, NOW)
43
44
45if __debug__:
46 pyc_ext = ".pyc"
47else:
48 pyc_ext = ".pyo"
49
50
51TESTMOD = "ziptestmodule"
52TESTPACK = "ziptestpackage"
Just van Rossumd35c6db2003-01-02 12:55:48 +000053TESTPACK2 = "ziptestpackage2"
Martin v. Löwisa94568a2003-05-10 07:36:56 +000054TEMP_ZIP = os.path.abspath("junk95142" + os.extsep + "zip")
Just van Rossum52e14d62002-12-30 22:08:05 +000055
56class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
57
58 compression = ZIP_STORED
59
60 def setUp(self):
61 # We're reusing the zip archive path, so we must clear the
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000062 # cached directory info and linecache
63 linecache.clearcache()
Just van Rossum52e14d62002-12-30 22:08:05 +000064 zipimport._zip_directory_cache.clear()
65 ImportHooksBaseTestCase.setUp(self)
66
Thomas Heller354e3d92003-07-22 18:10:15 +000067 def doTest(self, expected_ext, files, *modules, **kw):
Just van Rossum52e14d62002-12-30 22:08:05 +000068 z = ZipFile(TEMP_ZIP, "w")
69 try:
70 for name, (mtime, data) in files.items():
71 zinfo = ZipInfo(name, time.localtime(mtime))
72 zinfo.compress_type = self.compression
73 z.writestr(zinfo, data)
74 z.close()
Thomas Heller354e3d92003-07-22 18:10:15 +000075
76 stuff = kw.get("stuff", None)
77 if stuff is not None:
78 # Prepend 'stuff' to the start of the zipfile
79 f = open(TEMP_ZIP, "rb")
80 data = f.read()
81 f.close()
82
83 f = open(TEMP_ZIP, "wb")
84 f.write(stuff)
85 f.write(data)
86 f.close()
87
Just van Rossum52e14d62002-12-30 22:08:05 +000088 sys.path.insert(0, TEMP_ZIP)
89
90 mod = __import__(".".join(modules), globals(), locals(),
91 ["__dummy__"])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000092
93 call = kw.get('call')
94 if call is not None:
95 call(mod)
96
Just van Rossum9a3129c2003-01-03 11:18:56 +000097 if expected_ext:
98 file = mod.get_file()
99 self.assertEquals(file, os.path.join(TEMP_ZIP,
Just van Rossum6706c4d2003-01-09 22:27:10 +0000100 *modules) + expected_ext)
Just van Rossum52e14d62002-12-30 22:08:05 +0000101 finally:
102 z.close()
103 os.remove(TEMP_ZIP)
104
105 def testAFakeZlib(self):
106 #
107 # This could cause a stack overflow before: importing zlib.py
108 # from a compressed archive would cause zlib to be imported
109 # which would find zlib.py in the archive, which would... etc.
110 #
111 # This test *must* be executed first: it must be the first one
112 # to trigger zipimport to import zlib (zipimport caches the
113 # zlib.decompress function object, after which the problem being
114 # tested here wouldn't be a problem anymore...
115 # (Hence the 'A' in the test method name: to make it the first
116 # item in a list sorted by name, like unittest.makeSuite() does.)
117 #
Just van Rossum59498542003-11-18 23:00:55 +0000118 # This test fails on platforms on which the zlib module is
119 # statically linked, but the problem it tests for can't
120 # occur in that case (builtin modules are always found first),
121 # so we'll simply skip it then. Bug #765456.
122 #
123 if "zlib" in sys.builtin_module_names:
124 return
Just van Rossum52e14d62002-12-30 22:08:05 +0000125 if "zlib" in sys.modules:
126 del sys.modules["zlib"]
127 files = {"zlib.py": (NOW, test_src)}
128 try:
129 self.doTest(".py", files, "zlib")
130 except ImportError:
131 if self.compression != ZIP_DEFLATED:
132 self.fail("expected test to not raise ImportError")
133 else:
134 if self.compression != ZIP_STORED:
135 self.fail("expected test to raise ImportError")
136
137 def testPy(self):
138 files = {TESTMOD + ".py": (NOW, test_src)}
139 self.doTest(".py", files, TESTMOD)
140
141 def testPyc(self):
142 files = {TESTMOD + pyc_ext: (NOW, test_pyc)}
143 self.doTest(pyc_ext, files, TESTMOD)
144
145 def testBoth(self):
146 files = {TESTMOD + ".py": (NOW, test_src),
147 TESTMOD + pyc_ext: (NOW, test_pyc)}
148 self.doTest(pyc_ext, files, TESTMOD)
149
Just van Rossum9a3129c2003-01-03 11:18:56 +0000150 def testEmptyPy(self):
151 files = {TESTMOD + ".py": (NOW, "")}
152 self.doTest(None, files, TESTMOD)
153
Just van Rossum52e14d62002-12-30 22:08:05 +0000154 def testBadMagic(self):
155 # make pyc magic word invalid, forcing loading from .py
156 m0 = ord(test_pyc[0])
157 m0 ^= 0x04 # flip an arbitrary bit
158 badmagic_pyc = chr(m0) + test_pyc[1:]
159 files = {TESTMOD + ".py": (NOW, test_src),
160 TESTMOD + pyc_ext: (NOW, badmagic_pyc)}
161 self.doTest(".py", files, TESTMOD)
162
163 def testBadMagic2(self):
164 # make pyc magic word invalid, causing an ImportError
165 m0 = ord(test_pyc[0])
166 m0 ^= 0x04 # flip an arbitrary bit
167 badmagic_pyc = chr(m0) + test_pyc[1:]
168 files = {TESTMOD + pyc_ext: (NOW, badmagic_pyc)}
169 try:
170 self.doTest(".py", files, TESTMOD)
171 except ImportError:
172 pass
173 else:
174 self.fail("expected ImportError; import from bad pyc")
175
176 def testBadMTime(self):
177 t3 = ord(test_pyc[7])
178 t3 ^= 0x02 # flip the second bit -- not the first as that one
179 # isn't stored in the .py's mtime in the zip archive.
180 badtime_pyc = test_pyc[:7] + chr(t3) + test_pyc[8:]
181 files = {TESTMOD + ".py": (NOW, test_src),
182 TESTMOD + pyc_ext: (NOW, badtime_pyc)}
183 self.doTest(".py", files, TESTMOD)
184
185 def testPackage(self):
186 packdir = TESTPACK + os.sep
187 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
188 packdir + TESTMOD + pyc_ext: (NOW, test_pyc)}
189 self.doTest(pyc_ext, files, TESTPACK, TESTMOD)
190
191 def testDeepPackage(self):
192 packdir = TESTPACK + os.sep
Just van Rossumd35c6db2003-01-02 12:55:48 +0000193 packdir2 = packdir + TESTPACK2 + os.sep
Just van Rossum52e14d62002-12-30 22:08:05 +0000194 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
195 packdir2 + "__init__" + pyc_ext: (NOW, test_pyc),
196 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)}
Just van Rossumd35c6db2003-01-02 12:55:48 +0000197 self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD)
Just van Rossum52e14d62002-12-30 22:08:05 +0000198
Neal Norwitzb155b622006-01-23 07:52:13 +0000199 def testZipImporterMethods(self):
200 packdir = TESTPACK + os.sep
201 packdir2 = packdir + TESTPACK2 + os.sep
202 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
203 packdir2 + "__init__" + pyc_ext: (NOW, test_pyc),
204 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)}
205
206 z = ZipFile(TEMP_ZIP, "w")
207 try:
208 for name, (mtime, data) in files.items():
209 zinfo = ZipInfo(name, time.localtime(mtime))
210 zinfo.compress_type = self.compression
211 z.writestr(zinfo, data)
212 z.close()
213
214 zi = zipimport.zipimporter(TEMP_ZIP)
215 self.assertEquals(zi.is_package(TESTPACK), True)
216 zi.load_module(TESTPACK)
Tim Petersbc29c1a2006-01-23 21:28:42 +0000217
Neal Norwitzb155b622006-01-23 07:52:13 +0000218 self.assertEquals(zi.is_package(packdir + '__init__'), False)
219 self.assertEquals(zi.is_package(packdir + TESTPACK2), True)
220 self.assertEquals(zi.is_package(packdir2 + TESTMOD), False)
221
222 mod_name = packdir2 + TESTMOD
Tim Peters68f2d002006-01-23 22:19:24 +0000223 mod = __import__(module_path_to_dotted_name(mod_name))
Neal Norwitzb155b622006-01-23 07:52:13 +0000224 self.assertEquals(zi.get_source(TESTPACK), None)
225 self.assertEquals(zi.get_source(mod_name), None)
226 finally:
227 z.close()
228 os.remove(TEMP_ZIP)
229
Just van Rossum52e14d62002-12-30 22:08:05 +0000230 def testGetData(self):
231 z = ZipFile(TEMP_ZIP, "w")
232 z.compression = self.compression
233 try:
234 name = "testdata.dat"
235 data = "".join([chr(x) for x in range(256)]) * 500
236 z.writestr(name, data)
237 z.close()
238 zi = zipimport.zipimporter(TEMP_ZIP)
239 self.assertEquals(data, zi.get_data(name))
Neal Norwitzb155b622006-01-23 07:52:13 +0000240 self.assert_('zipimporter object' in repr(zi))
Just van Rossum52e14d62002-12-30 22:08:05 +0000241 finally:
242 z.close()
243 os.remove(TEMP_ZIP)
244
245 def testImporterAttr(self):
246 src = """if 1: # indent hack
247 def get_file():
248 return __file__
Just van Rossumd35c6db2003-01-02 12:55:48 +0000249 if __loader__.get_data("some.data") != "some data":
Just van Rossum52e14d62002-12-30 22:08:05 +0000250 raise AssertionError, "bad data"\n"""
251 pyc = make_pyc(compile(src, "<???>", "exec"), NOW)
252 files = {TESTMOD + pyc_ext: (NOW, pyc),
253 "some.data": (NOW, "some data")}
254 self.doTest(pyc_ext, files, TESTMOD)
255
Thomas Heller354e3d92003-07-22 18:10:15 +0000256 def testImport_WithStuff(self):
257 # try importing from a zipfile which contains additional
258 # stuff at the beginning of the file
259 files = {TESTMOD + ".py": (NOW, test_src)}
260 self.doTest(".py", files, TESTMOD,
261 stuff="Some Stuff"*31)
Just van Rossum52e14d62002-12-30 22:08:05 +0000262
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000263 def assertModuleSource(self, module):
264 self.assertEqual(inspect.getsource(module), test_src)
265
266 def testGetSource(self):
267 files = {TESTMOD + ".py": (NOW, test_src)}
268 self.doTest(".py", files, TESTMOD, call=self.assertModuleSource)
269
270 def testGetCompiledSource(self):
271 pyc = make_pyc(compile(test_src, "<???>", "exec"), NOW)
272 files = {TESTMOD + ".py": (NOW, test_src),
273 TESTMOD + pyc_ext: (NOW, pyc)}
274 self.doTest(pyc_ext, files, TESTMOD, call=self.assertModuleSource)
275
276 def runDoctest(self, callback):
277 files = {TESTMOD + ".py": (NOW, test_src),
278 "xyz.txt": (NOW, ">>> log.append(True)\n")}
279 self.doTest(".py", files, TESTMOD, call=callback)
280
281 def doDoctestFile(self, module):
282 log = []
283 old_master, doctest.master = doctest.master, None
284 try:
285 doctest.testfile(
286 'xyz.txt', package=module, module_relative=True,
287 globs=locals()
288 )
289 finally:
290 doctest.master = old_master
291 self.assertEqual(log,[True])
292
293 def testDoctestFile(self):
294 self.runDoctest(self.doDoctestFile)
295
296 def doDoctestSuite(self, module):
297 log = []
298 doctest.DocFileTest(
299 'xyz.txt', package=module, module_relative=True,
300 globs=locals()
301 ).run()
302 self.assertEqual(log,[True])
303
304 def testDoctestSuite(self):
305 self.runDoctest(self.doDoctestSuite)
306
307
308 def doTraceback(self, module):
309 try:
310 module.do_raise()
311 except:
312 tb = sys.exc_info()[2].tb_next
313
314 f,lno,n,line = extract_tb(tb, 1)[0]
315 self.assertEqual(line, raise_src.strip())
316
317 f,lno,n,line = extract_stack(tb.tb_frame, 1)[0]
318 self.assertEqual(line, raise_src.strip())
319
320 s = StringIO.StringIO()
321 print_tb(tb, 1, s)
322 self.failUnless(s.getvalue().endswith(raise_src))
323 else:
324 raise AssertionError("This ought to be impossible")
325
326 def testTraceback(self):
327 files = {TESTMOD + ".py": (NOW, raise_src)}
328 self.doTest(None, files, TESTMOD, call=self.doTraceback)
329
330
Just van Rossum52e14d62002-12-30 22:08:05 +0000331class CompressedZipImportTestCase(UncompressedZipImportTestCase):
332 compression = ZIP_DEFLATED
333
334
Neal Norwitzb155b622006-01-23 07:52:13 +0000335class BadFileZipImportTestCase(unittest.TestCase):
336 def assertZipFailure(self, filename):
337 self.assertRaises(zipimport.ZipImportError,
338 zipimport.zipimporter, filename)
339
340 def testNoFile(self):
341 self.assertZipFailure('AdfjdkFJKDFJjdklfjs')
342
343 def testEmptyFilename(self):
344 self.assertZipFailure('')
345
346 def testBadArgs(self):
347 self.assertRaises(TypeError, zipimport.zipimporter, None)
348 self.assertRaises(TypeError, zipimport.zipimporter, TESTMOD, kwd=None)
349
350 def testFilenameTooLong(self):
351 self.assertZipFailure('A' * 33000)
352
353 def testEmptyFile(self):
354 test_support.unlink(TESTMOD)
355 open(TESTMOD, 'w+').close()
356 self.assertZipFailure(TESTMOD)
357
358 def testFileUnreadable(self):
359 test_support.unlink(TESTMOD)
360 fd = os.open(TESTMOD, os.O_CREAT, 000)
Tim Peters68f2d002006-01-23 22:19:24 +0000361 try:
362 os.close(fd)
363 self.assertZipFailure(TESTMOD)
364 finally:
365 # If we leave "the read-only bit" set on Windows, nothing can
366 # delete TESTMOD, and later tests suffer bogus failures.
367 os.chmod(TESTMOD, 0666)
368 test_support.unlink(TESTMOD)
Neal Norwitzb155b622006-01-23 07:52:13 +0000369
370 def testNotZipFile(self):
371 test_support.unlink(TESTMOD)
372 fp = open(TESTMOD, 'w+')
373 fp.write('a' * 22)
374 fp.close()
375 self.assertZipFailure(TESTMOD)
376
Neal Norwitzdbc95f42006-01-23 08:48:03 +0000377 # XXX: disabled until this works on Big-endian machines
378 def _testBogusZipFile(self):
Neal Norwitzb155b622006-01-23 07:52:13 +0000379 test_support.unlink(TESTMOD)
380 fp = open(TESTMOD, 'w+')
381 fp.write(struct.pack('=I', 0x06054B50))
382 fp.write('a' * 18)
383 fp.close()
384 z = zipimport.zipimporter(TESTMOD)
385
386 try:
387 self.assertRaises(TypeError, z.find_module, None)
388 self.assertRaises(TypeError, z.load_module, None)
389 self.assertRaises(TypeError, z.is_package, None)
390 self.assertRaises(TypeError, z.get_code, None)
391 self.assertRaises(TypeError, z.get_data, None)
392 self.assertRaises(TypeError, z.get_source, None)
393
394 error = zipimport.ZipImportError
395 self.assertEqual(z.find_module('abc'), None)
396
397 self.assertRaises(error, z.load_module, 'abc')
398 self.assertRaises(error, z.get_code, 'abc')
399 self.assertRaises(IOError, z.get_data, 'abc')
400 self.assertRaises(error, z.get_source, 'abc')
401 self.assertRaises(error, z.is_package, 'abc')
402 finally:
403 zipimport._zip_directory_cache.clear()
404
405
406def cleanup():
407 # this is necessary if test is run repeated (like when finding leaks)
408 global test_imported
409 if test_imported:
410 zipimport._zip_directory_cache.clear()
411 if hasattr(UncompressedZipImportTestCase, 'testAFakeZlib'):
412 delattr(UncompressedZipImportTestCase, 'testAFakeZlib')
413 if hasattr(CompressedZipImportTestCase, 'testAFakeZlib'):
414 delattr(CompressedZipImportTestCase, 'testAFakeZlib')
415 test_imported = True
416
Neal Norwitz5c1ba532003-02-17 18:05:20 +0000417def test_main():
Neal Norwitzb155b622006-01-23 07:52:13 +0000418 cleanup()
419 try:
420 test_support.run_unittest(
421 UncompressedZipImportTestCase,
422 CompressedZipImportTestCase,
423 BadFileZipImportTestCase,
424 )
425 finally:
426 test_support.unlink(TESTMOD)
Neal Norwitz5c1ba532003-02-17 18:05:20 +0000427
428if __name__ == "__main__":
429 test_main()