blob: 07520a78eb130bc4a04c4dfd7272a58b51e6f25c [file] [log] [blame]
Just van Rossum52e14d62002-12-30 22:08:05 +00001import sys
2import os
3import marshal
4import imp
5import struct
6import time
7
8import zlib # implied prerequisite
9from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED
10from test import test_support
11from test.test_importhooks import ImportHooksBaseTestCase, test_src, test_co
12
13import zipimport
14
15
16def make_pyc(co, mtime):
17 data = marshal.dumps(co)
18 pyc = imp.get_magic() + struct.pack("<i", mtime) + data
19 return pyc
20
21NOW = time.time()
22test_pyc = make_pyc(test_co, NOW)
23
24
25if __debug__:
26 pyc_ext = ".pyc"
27else:
28 pyc_ext = ".pyo"
29
30
31TESTMOD = "ziptestmodule"
32TESTPACK = "ziptestpackage"
33TEMP_ZIP = "junk95142.zip"
34
35
36class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
37
38 compression = ZIP_STORED
39
40 def setUp(self):
41 # We're reusing the zip archive path, so we must clear the
42 # cached directory info.
43 zipimport._zip_directory_cache.clear()
44 ImportHooksBaseTestCase.setUp(self)
45
46 def doTest(self, expected_ext, files, *modules):
47 z = ZipFile(TEMP_ZIP, "w")
48 try:
49 for name, (mtime, data) in files.items():
50 zinfo = ZipInfo(name, time.localtime(mtime))
51 zinfo.compress_type = self.compression
52 z.writestr(zinfo, data)
53 z.close()
54 sys.path.insert(0, TEMP_ZIP)
55
56 mod = __import__(".".join(modules), globals(), locals(),
57 ["__dummy__"])
58 file = mod.get_file()
59 self.assertEquals(file, os.path.join(TEMP_ZIP,
60 os.sep.join(modules) + expected_ext))
61 finally:
62 z.close()
63 os.remove(TEMP_ZIP)
64
65 def testAFakeZlib(self):
66 #
67 # This could cause a stack overflow before: importing zlib.py
68 # from a compressed archive would cause zlib to be imported
69 # which would find zlib.py in the archive, which would... etc.
70 #
71 # This test *must* be executed first: it must be the first one
72 # to trigger zipimport to import zlib (zipimport caches the
73 # zlib.decompress function object, after which the problem being
74 # tested here wouldn't be a problem anymore...
75 # (Hence the 'A' in the test method name: to make it the first
76 # item in a list sorted by name, like unittest.makeSuite() does.)
77 #
78 if "zlib" in sys.modules:
79 del sys.modules["zlib"]
80 files = {"zlib.py": (NOW, test_src)}
81 try:
82 self.doTest(".py", files, "zlib")
83 except ImportError:
84 if self.compression != ZIP_DEFLATED:
85 self.fail("expected test to not raise ImportError")
86 else:
87 if self.compression != ZIP_STORED:
88 self.fail("expected test to raise ImportError")
89
90 def testPy(self):
91 files = {TESTMOD + ".py": (NOW, test_src)}
92 self.doTest(".py", files, TESTMOD)
93
94 def testPyc(self):
95 files = {TESTMOD + pyc_ext: (NOW, test_pyc)}
96 self.doTest(pyc_ext, files, TESTMOD)
97
98 def testBoth(self):
99 files = {TESTMOD + ".py": (NOW, test_src),
100 TESTMOD + pyc_ext: (NOW, test_pyc)}
101 self.doTest(pyc_ext, files, TESTMOD)
102
103 def testBadMagic(self):
104 # make pyc magic word invalid, forcing loading from .py
105 m0 = ord(test_pyc[0])
106 m0 ^= 0x04 # flip an arbitrary bit
107 badmagic_pyc = chr(m0) + test_pyc[1:]
108 files = {TESTMOD + ".py": (NOW, test_src),
109 TESTMOD + pyc_ext: (NOW, badmagic_pyc)}
110 self.doTest(".py", files, TESTMOD)
111
112 def testBadMagic2(self):
113 # make pyc magic word invalid, causing an ImportError
114 m0 = ord(test_pyc[0])
115 m0 ^= 0x04 # flip an arbitrary bit
116 badmagic_pyc = chr(m0) + test_pyc[1:]
117 files = {TESTMOD + pyc_ext: (NOW, badmagic_pyc)}
118 try:
119 self.doTest(".py", files, TESTMOD)
120 except ImportError:
121 pass
122 else:
123 self.fail("expected ImportError; import from bad pyc")
124
125 def testBadMTime(self):
126 t3 = ord(test_pyc[7])
127 t3 ^= 0x02 # flip the second bit -- not the first as that one
128 # isn't stored in the .py's mtime in the zip archive.
129 badtime_pyc = test_pyc[:7] + chr(t3) + test_pyc[8:]
130 files = {TESTMOD + ".py": (NOW, test_src),
131 TESTMOD + pyc_ext: (NOW, badtime_pyc)}
132 self.doTest(".py", files, TESTMOD)
133
134 def testPackage(self):
135 packdir = TESTPACK + os.sep
136 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
137 packdir + TESTMOD + pyc_ext: (NOW, test_pyc)}
138 self.doTest(pyc_ext, files, TESTPACK, TESTMOD)
139
140 def testDeepPackage(self):
141 packdir = TESTPACK + os.sep
142 packdir2 = packdir + packdir
143 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
144 packdir2 + "__init__" + pyc_ext: (NOW, test_pyc),
145 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)}
146 self.doTest(pyc_ext, files, TESTPACK, TESTPACK, TESTMOD)
147
148 def testGetData(self):
149 z = ZipFile(TEMP_ZIP, "w")
150 z.compression = self.compression
151 try:
152 name = "testdata.dat"
153 data = "".join([chr(x) for x in range(256)]) * 500
154 z.writestr(name, data)
155 z.close()
156 zi = zipimport.zipimporter(TEMP_ZIP)
157 self.assertEquals(data, zi.get_data(name))
158 finally:
159 z.close()
160 os.remove(TEMP_ZIP)
161
162 def testImporterAttr(self):
163 src = """if 1: # indent hack
164 def get_file():
165 return __file__
166 if __importer__.get_data("some.data") != "some data":
167 raise AssertionError, "bad data"\n"""
168 pyc = make_pyc(compile(src, "<???>", "exec"), NOW)
169 files = {TESTMOD + pyc_ext: (NOW, pyc),
170 "some.data": (NOW, "some data")}
171 self.doTest(pyc_ext, files, TESTMOD)
172
173
174class CompressedZipImportTestCase(UncompressedZipImportTestCase):
175 compression = ZIP_DEFLATED
176
177
178if __name__ == "__main__":
179 test_support.run_unittest(UncompressedZipImportTestCase)
180 test_support.run_unittest(CompressedZipImportTestCase)