blob: d6f55341be0fed20b38dcad0689aa747cd0fa848 [file] [log] [blame]
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001# We can test part of the module without zlib.
Guido van Rossum368f04a2000-04-10 13:23:04 +00002try:
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00003 import zlib
4except ImportError:
5 zlib = None
Tim Petersa45cacf2004-08-20 03:47:14 +00006
Thomas Wouters0e3f5912006-08-11 14:57:12 +00007import zipfile, os, unittest, sys, shutil
Tim Petersa19a1682001-03-29 04:36:09 +00008
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00009from StringIO import StringIO
10from tempfile import TemporaryFile
Tim Petersa19a1682001-03-29 04:36:09 +000011
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000012from test.test_support import TESTFN, run_unittest
Guido van Rossum368f04a2000-04-10 13:23:04 +000013
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000014TESTFN2 = TESTFN + "2"
Guido van Rossum368f04a2000-04-10 13:23:04 +000015
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000016class TestsWithSourceFile(unittest.TestCase):
17 def setUp(self):
18 line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000))
19 self.data = '\n'.join(line_gen)
Fred Drake6e7e4852001-02-28 05:34:16 +000020
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000021 # Make a source file with some lines
22 fp = open(TESTFN, "wb")
23 fp.write(self.data)
24 fp.close()
Tim Peters7d3bad62001-04-04 18:56:49 +000025
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000026 def zipTest(self, f, compression):
27 # Create the ZIP archive
28 zipfp = zipfile.ZipFile(f, "w", compression)
29 zipfp.write(TESTFN, "another"+os.extsep+"name")
30 zipfp.write(TESTFN, TESTFN)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000031 zipfp.writestr("strfile", self.data)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000032 zipfp.close()
Tim Peters7d3bad62001-04-04 18:56:49 +000033
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000034 # Read the ZIP archive
35 zipfp = zipfile.ZipFile(f, "r", compression)
36 self.assertEqual(zipfp.read(TESTFN), self.data)
37 self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000038 self.assertEqual(zipfp.read("strfile"), self.data)
39
40 # Print the ZIP directory
41 fp = StringIO()
42 stdout = sys.stdout
43 try:
44 sys.stdout = fp
45
46 zipfp.printdir()
47 finally:
48 sys.stdout = stdout
49
50 directory = fp.getvalue()
51 lines = directory.splitlines()
52 self.assertEquals(len(lines), 4) # Number of files + header
53
54 self.assert_('File Name' in lines[0])
55 self.assert_('Modified' in lines[0])
56 self.assert_('Size' in lines[0])
57
58 fn, date, time, size = lines[1].split()
59 self.assertEquals(fn, 'another.name')
60 # XXX: timestamp is not tested
61 self.assertEquals(size, str(len(self.data)))
62
63 # Check the namelist
64 names = zipfp.namelist()
65 self.assertEquals(len(names), 3)
66 self.assert_(TESTFN in names)
67 self.assert_("another"+os.extsep+"name" in names)
68 self.assert_("strfile" in names)
69
70 # Check infolist
71 infos = zipfp.infolist()
72 names = [ i.filename for i in infos ]
73 self.assertEquals(len(names), 3)
74 self.assert_(TESTFN in names)
75 self.assert_("another"+os.extsep+"name" in names)
76 self.assert_("strfile" in names)
77 for i in infos:
78 self.assertEquals(i.file_size, len(self.data))
79
80 # check getinfo
81 for nm in (TESTFN, "another"+os.extsep+"name", "strfile"):
82 info = zipfp.getinfo(nm)
83 self.assertEquals(info.filename, nm)
84 self.assertEquals(info.file_size, len(self.data))
85
86 # Check that testzip doesn't raise an exception
87 zipfp.testzip()
88
89
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000090 zipfp.close()
Tim Peters7d3bad62001-04-04 18:56:49 +000091
Thomas Wouters0e3f5912006-08-11 14:57:12 +000092
93
94
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000095 def testStored(self):
96 for f in (TESTFN2, TemporaryFile(), StringIO()):
97 self.zipTest(f, zipfile.ZIP_STORED)
Raymond Hettingerc0fac962003-06-27 22:25:03 +000098
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000099 if zlib:
100 def testDeflated(self):
101 for f in (TESTFN2, TemporaryFile(), StringIO()):
102 self.zipTest(f, zipfile.ZIP_DEFLATED)
Raymond Hettingerc0fac962003-06-27 22:25:03 +0000103
Georg Brandl8f7c54e2006-02-20 08:40:38 +0000104 def testAbsoluteArcnames(self):
105 zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
106 zipfp.write(TESTFN, "/absolute")
107 zipfp.close()
108
109 zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
110 self.assertEqual(zipfp.namelist(), ["absolute"])
111 zipfp.close()
Tim Peters32cbc962006-02-20 21:42:18 +0000112
Georg Brandl8f7c54e2006-02-20 08:40:38 +0000113
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +0000114 def tearDown(self):
115 os.remove(TESTFN)
116 os.remove(TESTFN2)
117
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000118class TestZip64InSmallFiles(unittest.TestCase):
119 # These tests test the ZIP64 functionality without using large files,
120 # see test_zipfile64 for proper tests.
121
122 def setUp(self):
123 self._limit = zipfile.ZIP64_LIMIT
124 zipfile.ZIP64_LIMIT = 5
125
126 line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000))
127 self.data = '\n'.join(line_gen)
128
129 # Make a source file with some lines
130 fp = open(TESTFN, "wb")
131 fp.write(self.data)
132 fp.close()
133
134 def largeFileExceptionTest(self, f, compression):
135 zipfp = zipfile.ZipFile(f, "w", compression)
136 self.assertRaises(zipfile.LargeZipFile,
137 zipfp.write, TESTFN, "another"+os.extsep+"name")
138 zipfp.close()
139
140 def largeFileExceptionTest2(self, f, compression):
141 zipfp = zipfile.ZipFile(f, "w", compression)
142 self.assertRaises(zipfile.LargeZipFile,
143 zipfp.writestr, "another"+os.extsep+"name", self.data)
144 zipfp.close()
145
146 def testLargeFileException(self):
147 for f in (TESTFN2, TemporaryFile(), StringIO()):
148 self.largeFileExceptionTest(f, zipfile.ZIP_STORED)
149 self.largeFileExceptionTest2(f, zipfile.ZIP_STORED)
150
151 def zipTest(self, f, compression):
152 # Create the ZIP archive
153 zipfp = zipfile.ZipFile(f, "w", compression, allowZip64=True)
154 zipfp.write(TESTFN, "another"+os.extsep+"name")
155 zipfp.write(TESTFN, TESTFN)
156 zipfp.writestr("strfile", self.data)
157 zipfp.close()
158
159 # Read the ZIP archive
160 zipfp = zipfile.ZipFile(f, "r", compression)
161 self.assertEqual(zipfp.read(TESTFN), self.data)
162 self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
163 self.assertEqual(zipfp.read("strfile"), self.data)
164
165 # Print the ZIP directory
166 fp = StringIO()
167 stdout = sys.stdout
168 try:
169 sys.stdout = fp
170
171 zipfp.printdir()
172 finally:
173 sys.stdout = stdout
174
175 directory = fp.getvalue()
176 lines = directory.splitlines()
177 self.assertEquals(len(lines), 4) # Number of files + header
178
179 self.assert_('File Name' in lines[0])
180 self.assert_('Modified' in lines[0])
181 self.assert_('Size' in lines[0])
182
183 fn, date, time, size = lines[1].split()
184 self.assertEquals(fn, 'another.name')
185 # XXX: timestamp is not tested
186 self.assertEquals(size, str(len(self.data)))
187
188 # Check the namelist
189 names = zipfp.namelist()
190 self.assertEquals(len(names), 3)
191 self.assert_(TESTFN in names)
192 self.assert_("another"+os.extsep+"name" in names)
193 self.assert_("strfile" in names)
194
195 # Check infolist
196 infos = zipfp.infolist()
197 names = [ i.filename for i in infos ]
198 self.assertEquals(len(names), 3)
199 self.assert_(TESTFN in names)
200 self.assert_("another"+os.extsep+"name" in names)
201 self.assert_("strfile" in names)
202 for i in infos:
203 self.assertEquals(i.file_size, len(self.data))
204
205 # check getinfo
206 for nm in (TESTFN, "another"+os.extsep+"name", "strfile"):
207 info = zipfp.getinfo(nm)
208 self.assertEquals(info.filename, nm)
209 self.assertEquals(info.file_size, len(self.data))
210
211 # Check that testzip doesn't raise an exception
212 zipfp.testzip()
213
214
215 zipfp.close()
216
217 def testStored(self):
218 for f in (TESTFN2, TemporaryFile(), StringIO()):
219 self.zipTest(f, zipfile.ZIP_STORED)
220
221
222 if zlib:
223 def testDeflated(self):
224 for f in (TESTFN2, TemporaryFile(), StringIO()):
225 self.zipTest(f, zipfile.ZIP_DEFLATED)
226
227 def testAbsoluteArcnames(self):
228 zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, allowZip64=True)
229 zipfp.write(TESTFN, "/absolute")
230 zipfp.close()
231
232 zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
233 self.assertEqual(zipfp.namelist(), ["absolute"])
234 zipfp.close()
235
236
237 def tearDown(self):
238 zipfile.ZIP64_LIMIT = self._limit
239 os.remove(TESTFN)
240 os.remove(TESTFN2)
241
242class PyZipFileTests(unittest.TestCase):
243 def testWritePyfile(self):
244 zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
245 fn = __file__
246 if fn.endswith('.pyc') or fn.endswith('.pyo'):
247 fn = fn[:-1]
248
249 zipfp.writepy(fn)
250
251 bn = os.path.basename(fn)
252 self.assert_(bn not in zipfp.namelist())
253 self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist())
254 zipfp.close()
255
256
257 zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
258 fn = __file__
259 if fn.endswith('.pyc') or fn.endswith('.pyo'):
260 fn = fn[:-1]
261
262 zipfp.writepy(fn, "testpackage")
263
264 bn = "%s/%s"%("testpackage", os.path.basename(fn))
265 self.assert_(bn not in zipfp.namelist())
266 self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist())
267 zipfp.close()
268
269 def testWritePythonPackage(self):
270 import email
271 packagedir = os.path.dirname(email.__file__)
272
273 zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
274 zipfp.writepy(packagedir)
275
276 # Check for a couple of modules at different levels of the hieararchy
277 names = zipfp.namelist()
278 self.assert_('email/__init__.pyo' in names or 'email/__init__.pyc' in names)
279 self.assert_('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names)
280
281 def testWritePythonDirectory(self):
282 os.mkdir(TESTFN2)
283 try:
284 fp = open(os.path.join(TESTFN2, "mod1.py"), "w")
Guido van Rossum43fc78d2007-02-09 22:18:41 +0000285 fp.write("print(42)\n")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000286 fp.close()
287
288 fp = open(os.path.join(TESTFN2, "mod2.py"), "w")
Guido van Rossum43fc78d2007-02-09 22:18:41 +0000289 fp.write("print(42 * 42)\n")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000290 fp.close()
291
292 fp = open(os.path.join(TESTFN2, "mod2.txt"), "w")
293 fp.write("bla bla bla\n")
294 fp.close()
295
296 zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
297 zipfp.writepy(TESTFN2)
298
299 names = zipfp.namelist()
300 self.assert_('mod1.pyc' in names or 'mod1.pyo' in names)
301 self.assert_('mod2.pyc' in names or 'mod2.pyo' in names)
302 self.assert_('mod2.txt' not in names)
303
304 finally:
305 shutil.rmtree(TESTFN2)
306
307
308
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +0000309class OtherTests(unittest.TestCase):
Thomas Wouterscf297e42007-02-23 15:07:44 +0000310 def testCreateNonExistentFileForAppend(self):
311 if os.path.exists(TESTFN):
312 os.unlink(TESTFN)
313
314 filename = 'testfile.txt'
315 content = 'hello, world. this is some content.'
316
317 try:
318 zf = zipfile.ZipFile(TESTFN, 'a')
319 zf.writestr(filename, content)
320 zf.close()
321 except IOError:
322 self.fail('Could not append data to a non-existent zip file.')
323
324 self.assert_(os.path.exists(TESTFN))
325
326 zf = zipfile.ZipFile(TESTFN, 'r')
327 self.assertEqual(zf.read(filename), content)
328 zf.close()
329
330 os.unlink(TESTFN)
331
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +0000332 def testCloseErroneousFile(self):
333 # This test checks that the ZipFile constructor closes the file object
334 # it opens if there's an error in the file. If it doesn't, the traceback
335 # holds a reference to the ZipFile object and, indirectly, the file object.
336 # On Windows, this causes the os.unlink() call to fail because the
337 # underlying file is still open. This is SF bug #412214.
338 #
339 fp = open(TESTFN, "w")
340 fp.write("this is not a legal zip file\n")
341 fp.close()
342 try:
343 zf = zipfile.ZipFile(TESTFN)
344 except zipfile.BadZipfile:
345 os.unlink(TESTFN)
346
347 def testNonExistentFileRaisesIOError(self):
348 # make sure we don't raise an AttributeError when a partially-constructed
349 # ZipFile instance is finalized; this tests for regression on SF tracker
350 # bug #403871.
351
352 # The bug we're testing for caused an AttributeError to be raised
353 # when a ZipFile instance was created for a file that did not
354 # exist; the .fp member was not initialized but was needed by the
355 # __del__() method. Since the AttributeError is in the __del__(),
356 # it is ignored, but the user should be sufficiently annoyed by
357 # the message on the output that regression will be noticed
358 # quickly.
359 self.assertRaises(IOError, zipfile.ZipFile, TESTFN)
360
361 def testClosedZipRaisesRuntimeError(self):
362 # Verify that testzip() doesn't swallow inappropriate exceptions.
363 data = StringIO()
364 zipf = zipfile.ZipFile(data, mode="w")
365 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
366 zipf.close()
367
368 # This is correct; calling .read on a closed ZipFile should throw
369 # a RuntimeError, and so should calling .testzip. An earlier
370 # version of .testzip would swallow this exception (and any other)
371 # and report that the first file in the archive was corrupt.
372 self.assertRaises(RuntimeError, zipf.testzip)
373
Thomas Wouterscf297e42007-02-23 15:07:44 +0000374
375class DecryptionTests(unittest.TestCase):
376 # This test checks that ZIP decryption works. Since the library does not
377 # support encryption at the moment, we use a pre-generated encrypted
378 # ZIP file
379
380 data = (
381 'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
382 '\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
383 '\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
384 'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
385 '\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
386 '\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
387 '\x00\x00L\x00\x00\x00\x00\x00' )
388
389 plain = 'zipfile.py encryption test'
390
391 def setUp(self):
392 fp = open(TESTFN, "wb")
393 fp.write(self.data)
394 fp.close()
395 self.zip = zipfile.ZipFile(TESTFN, "r")
396
397 def tearDown(self):
398 self.zip.close()
399 os.unlink(TESTFN)
400
401 def testNoPassword(self):
402 # Reading the encrypted file without password
403 # must generate a RunTime exception
404 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
405
406 def testBadPassword(self):
407 self.zip.setpassword("perl")
408 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
409
410 def testGoodPassword(self):
411 self.zip.setpassword("python")
412 self.assertEquals(self.zip.read("test.txt"), self.plain)
413
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +0000414def test_main():
Thomas Wouterscf297e42007-02-23 15:07:44 +0000415 run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests,
416 PyZipFileTests, DecryptionTests)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000417 #run_unittest(TestZip64InSmallFiles)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +0000418
419if __name__ == "__main__":
420 test_main()