blob: c334715f3d81b1fc87b0a51ac49f7342353cebc4 [file] [log] [blame]
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02001import contextlib
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002import importlib.util
Ezio Melotti74c96ec2009-07-08 22:24:06 +00003import io
Daniel Hillierda6ce582019-10-29 18:24:18 +11004import itertools
Ezio Melotti74c96ec2009-07-08 22:24:06 +00005import os
Serhiy Storchaka8606e952017-03-08 14:37:51 +02006import pathlib
Serhiy Storchaka503f9082016-02-08 00:02:25 +02007import posixpath
Ezio Melotti74c96ec2009-07-08 22:24:06 +00008import struct
Gregory P. Smith3f4db4a2019-09-10 17:14:11 +01009import subprocess
10import sys
Jason R. Coombsb2758ff2019-05-08 09:45:06 -040011import time
Ezio Melotti74c96ec2009-07-08 22:24:06 +000012import unittest
Berker Peksag2f1b8572019-09-12 17:13:44 +030013import unittest.mock as mock
Jason R. Coombsb2758ff2019-05-08 09:45:06 -040014import zipfile
Ezio Melotti74c96ec2009-07-08 22:24:06 +000015
Tim Petersa45cacf2004-08-20 03:47:14 +000016
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000017from tempfile import TemporaryFile
Serhiy Storchakafa6bc292013-07-22 21:00:11 +030018from random import randint, random, getrandbits
Tim Petersa19a1682001-03-29 04:36:09 +000019
Serhiy Storchaka61c4c442016-10-23 13:07:59 +030020from test.support import script_helper
Serhiy Storchaka8606e952017-03-08 14:37:51 +020021from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, temp_cwd,
Serhiy Storchakac5b75db2013-01-29 20:14:08 +020022 requires_zlib, requires_bz2, requires_lzma,
Victor Stinnerd6debb22017-03-27 16:05:26 +020023 captured_stdout)
Guido van Rossum368f04a2000-04-10 13:23:04 +000024
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000025TESTFN2 = TESTFN + "2"
Martin v. Löwis59e47792009-01-24 14:10:07 +000026TESTFNDIR = TESTFN + "d"
Guido van Rossumb5a755e2007-07-18 18:15:48 +000027FIXEDTEST_SIZE = 1000
Georg Brandl5ba11de2011-01-01 10:09:32 +000028DATAFILES_DIR = 'zipfile_datafiles'
Guido van Rossum368f04a2000-04-10 13:23:04 +000029
Christian Heimes790c8232008-01-07 21:14:23 +000030SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
31 ('ziptest2dir/_ziptest2', 'qawsedrftg'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -080032 ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
Christian Heimes790c8232008-01-07 21:14:23 +000033 ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')]
34
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +020035def getrandbytes(size):
36 return getrandbits(8 * size).to_bytes(size, 'little')
37
Serhiy Storchakafa6bc292013-07-22 21:00:11 +030038def get_files(test):
39 yield TESTFN2
40 with TemporaryFile() as f:
41 yield f
42 test.assertFalse(f.closed)
43 with io.BytesIO() as f:
44 yield f
45 test.assertFalse(f.closed)
Ezio Melotti76430242009-07-11 18:28:48 +000046
Serhiy Storchakafa6bc292013-07-22 21:00:11 +030047class AbstractTestsWithSourceFile:
48 @classmethod
49 def setUpClass(cls):
50 cls.line_gen = [bytes("Zipfile test line %d. random float: %f\n" %
51 (i, random()), "ascii")
52 for i in range(FIXEDTEST_SIZE)]
53 cls.data = b''.join(cls.line_gen)
54
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000055 def setUp(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000056 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +000057 with open(TESTFN, "wb") as fp:
58 fp.write(self.data)
Tim Peters7d3bad62001-04-04 18:56:49 +000059
Bo Baylesce237c72018-01-29 23:54:07 -060060 def make_test_archive(self, f, compression, compresslevel=None):
61 kwargs = {'compression': compression, 'compresslevel': compresslevel}
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000062 # Create the ZIP archive
Bo Baylesce237c72018-01-29 23:54:07 -060063 with zipfile.ZipFile(f, "w", **kwargs) as zipfp:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000064 zipfp.write(TESTFN, "another.name")
65 zipfp.write(TESTFN, TESTFN)
66 zipfp.writestr("strfile", self.data)
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +030067 with zipfp.open('written-open-w', mode='w') as f:
68 for line in self.line_gen:
69 f.write(line)
Tim Peters7d3bad62001-04-04 18:56:49 +000070
Bo Baylesce237c72018-01-29 23:54:07 -060071 def zip_test(self, f, compression, compresslevel=None):
72 self.make_test_archive(f, compression, compresslevel)
Guido van Rossumd8faa362007-04-27 19:54:29 +000073
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000074 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000075 with zipfile.ZipFile(f, "r", compression) as zipfp:
76 self.assertEqual(zipfp.read(TESTFN), self.data)
77 self.assertEqual(zipfp.read("another.name"), self.data)
78 self.assertEqual(zipfp.read("strfile"), self.data)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000079
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000080 # Print the ZIP directory
81 fp = io.StringIO()
82 zipfp.printdir(file=fp)
83 directory = fp.getvalue()
84 lines = directory.splitlines()
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +030085 self.assertEqual(len(lines), 5) # Number of files + header
Thomas Wouters0e3f5912006-08-11 14:57:12 +000086
Benjamin Peterson577473f2010-01-19 00:09:57 +000087 self.assertIn('File Name', lines[0])
88 self.assertIn('Modified', lines[0])
89 self.assertIn('Size', lines[0])
Thomas Wouters0e3f5912006-08-11 14:57:12 +000090
Ezio Melotti35386712009-12-31 13:22:41 +000091 fn, date, time_, size = lines[1].split()
92 self.assertEqual(fn, 'another.name')
93 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
94 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
95 self.assertEqual(size, str(len(self.data)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000097 # Check the namelist
98 names = zipfp.namelist()
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +030099 self.assertEqual(len(names), 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000100 self.assertIn(TESTFN, names)
101 self.assertIn("another.name", names)
102 self.assertIn("strfile", names)
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300103 self.assertIn("written-open-w", names)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000104
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000105 # Check infolist
106 infos = zipfp.infolist()
Ezio Melotti35386712009-12-31 13:22:41 +0000107 names = [i.filename for i in infos]
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300108 self.assertEqual(len(names), 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000109 self.assertIn(TESTFN, names)
110 self.assertIn("another.name", names)
111 self.assertIn("strfile", names)
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300112 self.assertIn("written-open-w", names)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000113 for i in infos:
Ezio Melotti35386712009-12-31 13:22:41 +0000114 self.assertEqual(i.file_size, len(self.data))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000115
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000116 # check getinfo
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300117 for nm in (TESTFN, "another.name", "strfile", "written-open-w"):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000118 info = zipfp.getinfo(nm)
Ezio Melotti35386712009-12-31 13:22:41 +0000119 self.assertEqual(info.filename, nm)
120 self.assertEqual(info.file_size, len(self.data))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000121
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000122 # Check that testzip doesn't raise an exception
123 zipfp.testzip()
Tim Peters7d3bad62001-04-04 18:56:49 +0000124
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300125 def test_basic(self):
126 for f in get_files(self):
127 self.zip_test(f, self.compression)
Raymond Hettingerc0fac962003-06-27 22:25:03 +0000128
Ezio Melottiafd0d112009-07-15 17:17:17 +0000129 def zip_open_test(self, f, compression):
130 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000131
132 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000133 with zipfile.ZipFile(f, "r", compression) as zipfp:
134 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +0000135 with zipfp.open(TESTFN) as zipopen1:
136 while True:
137 read_data = zipopen1.read(256)
138 if not read_data:
139 break
140 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000141
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000142 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +0000143 with zipfp.open("another.name") as zipopen2:
144 while True:
145 read_data = zipopen2.read(256)
146 if not read_data:
147 break
148 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000149
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000150 self.assertEqual(b''.join(zipdata1), self.data)
151 self.assertEqual(b''.join(zipdata2), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000152
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300153 def test_open(self):
154 for f in get_files(self):
155 self.zip_open_test(f, self.compression)
Georg Brandlb533e262008-05-25 18:19:30 +0000156
Serhiy Storchaka8606e952017-03-08 14:37:51 +0200157 def test_open_with_pathlike(self):
158 path = pathlib.Path(TESTFN2)
159 self.zip_open_test(path, self.compression)
160 with zipfile.ZipFile(path, "r", self.compression) as zipfp:
161 self.assertIsInstance(zipfp.filename, str)
162
Ezio Melottiafd0d112009-07-15 17:17:17 +0000163 def zip_random_open_test(self, f, compression):
164 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000165
166 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000167 with zipfile.ZipFile(f, "r", compression) as zipfp:
168 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +0000169 with zipfp.open(TESTFN) as zipopen1:
170 while True:
171 read_data = zipopen1.read(randint(1, 1024))
172 if not read_data:
173 break
174 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000175
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000176 self.assertEqual(b''.join(zipdata1), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000177
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300178 def test_random_open(self):
179 for f in get_files(self):
180 self.zip_random_open_test(f, self.compression)
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000181
Serhiy Storchakad2c07a52013-09-27 22:11:57 +0300182 def zip_read1_test(self, f, compression):
183 self.make_test_archive(f, compression)
184
185 # Read the ZIP archive
186 with zipfile.ZipFile(f, "r") as zipfp, \
187 zipfp.open(TESTFN) as zipopen:
188 zipdata = []
189 while True:
190 read_data = zipopen.read1(-1)
191 if not read_data:
192 break
193 zipdata.append(read_data)
194
195 self.assertEqual(b''.join(zipdata), self.data)
196
197 def test_read1(self):
198 for f in get_files(self):
199 self.zip_read1_test(f, self.compression)
200
201 def zip_read1_10_test(self, f, compression):
202 self.make_test_archive(f, compression)
203
204 # Read the ZIP archive
205 with zipfile.ZipFile(f, "r") as zipfp, \
206 zipfp.open(TESTFN) as zipopen:
207 zipdata = []
208 while True:
209 read_data = zipopen.read1(10)
210 self.assertLessEqual(len(read_data), 10)
211 if not read_data:
212 break
213 zipdata.append(read_data)
214
215 self.assertEqual(b''.join(zipdata), self.data)
216
217 def test_read1_10(self):
218 for f in get_files(self):
219 self.zip_read1_10_test(f, self.compression)
220
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000221 def zip_readline_read_test(self, f, compression):
222 self.make_test_archive(f, compression)
223
224 # Read the ZIP archive
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300225 with zipfile.ZipFile(f, "r") as zipfp, \
226 zipfp.open(TESTFN) as zipopen:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000227 data = b''
228 while True:
229 read = zipopen.readline()
230 if not read:
231 break
232 data += read
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000233
Brian Curtin8fb9b862010-11-18 02:15:28 +0000234 read = zipopen.read(100)
235 if not read:
236 break
237 data += read
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000238
239 self.assertEqual(data, self.data)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300240
241 def test_readline_read(self):
242 # Issue #7610: calls to readline() interleaved with calls to read().
243 for f in get_files(self):
244 self.zip_readline_read_test(f, self.compression)
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000245
Ezio Melottiafd0d112009-07-15 17:17:17 +0000246 def zip_readline_test(self, f, compression):
247 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000248
249 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000250 with zipfile.ZipFile(f, "r") as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000251 with zipfp.open(TESTFN) as zipopen:
252 for line in self.line_gen:
253 linedata = zipopen.readline()
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300254 self.assertEqual(linedata, line)
255
256 def test_readline(self):
257 for f in get_files(self):
258 self.zip_readline_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000259
Ezio Melottiafd0d112009-07-15 17:17:17 +0000260 def zip_readlines_test(self, f, compression):
261 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000262
263 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000264 with zipfile.ZipFile(f, "r") as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000265 with zipfp.open(TESTFN) as zipopen:
266 ziplines = zipopen.readlines()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000267 for line, zipline in zip(self.line_gen, ziplines):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300268 self.assertEqual(zipline, line)
269
270 def test_readlines(self):
271 for f in get_files(self):
272 self.zip_readlines_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000273
Ezio Melottiafd0d112009-07-15 17:17:17 +0000274 def zip_iterlines_test(self, f, compression):
275 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000276
277 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000278 with zipfile.ZipFile(f, "r") as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000279 with zipfp.open(TESTFN) as zipopen:
280 for line, zipline in zip(self.line_gen, zipopen):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300281 self.assertEqual(zipline, line)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300283 def test_iterlines(self):
284 for f in get_files(self):
285 self.zip_iterlines_test(f, self.compression)
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000286
Ezio Melottiafd0d112009-07-15 17:17:17 +0000287 def test_low_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000288 """Check for cases where compressed data is larger than original."""
Ezio Melotti74c96ec2009-07-08 22:24:06 +0000289 # Create the ZIP archive
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300290 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipfp:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000291 zipfp.writestr("strfile", '12')
Ezio Melotti74c96ec2009-07-08 22:24:06 +0000292
293 # Get an open object for strfile
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300294 with zipfile.ZipFile(TESTFN2, "r", self.compression) as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000295 with zipfp.open("strfile") as openobj:
296 self.assertEqual(openobj.read(1), b'1')
297 self.assertEqual(openobj.read(1), b'2')
Ezio Melotti74c96ec2009-07-08 22:24:06 +0000298
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300299 def test_writestr_compression(self):
300 zipfp = zipfile.ZipFile(TESTFN2, "w")
301 zipfp.writestr("b.txt", "hello world", compress_type=self.compression)
302 info = zipfp.getinfo('b.txt')
303 self.assertEqual(info.compress_type, self.compression)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200304
Bo Baylesce237c72018-01-29 23:54:07 -0600305 def test_writestr_compresslevel(self):
306 zipfp = zipfile.ZipFile(TESTFN2, "w", compresslevel=1)
307 zipfp.writestr("a.txt", "hello world", compress_type=self.compression)
308 zipfp.writestr("b.txt", "hello world", compress_type=self.compression,
309 compresslevel=2)
310
311 # Compression level follows the constructor.
312 a_info = zipfp.getinfo('a.txt')
313 self.assertEqual(a_info.compress_type, self.compression)
314 self.assertEqual(a_info._compresslevel, 1)
315
316 # Compression level is overridden.
317 b_info = zipfp.getinfo('b.txt')
318 self.assertEqual(b_info.compress_type, self.compression)
319 self.assertEqual(b_info._compresslevel, 2)
320
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300321 def test_read_return_size(self):
322 # Issue #9837: ZipExtFile.read() shouldn't return more bytes
323 # than requested.
324 for test_size in (1, 4095, 4096, 4097, 16384):
325 file_size = test_size + 1
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +0200326 junk = getrandbytes(file_size)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300327 with zipfile.ZipFile(io.BytesIO(), "w", self.compression) as zipf:
328 zipf.writestr('foo', junk)
329 with zipf.open('foo', 'r') as fp:
330 buf = fp.read(test_size)
331 self.assertEqual(len(buf), test_size)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200332
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200333 def test_truncated_zipfile(self):
334 fp = io.BytesIO()
335 with zipfile.ZipFile(fp, mode='w') as zipf:
336 zipf.writestr('strfile', self.data, compress_type=self.compression)
337 end_offset = fp.tell()
338 zipfiledata = fp.getvalue()
339
340 fp = io.BytesIO(zipfiledata)
341 with zipfile.ZipFile(fp) as zipf:
342 with zipf.open('strfile') as zipopen:
343 fp.truncate(end_offset - 20)
344 with self.assertRaises(EOFError):
345 zipopen.read()
346
347 fp = io.BytesIO(zipfiledata)
348 with zipfile.ZipFile(fp) as zipf:
349 with zipf.open('strfile') as zipopen:
350 fp.truncate(end_offset - 20)
351 with self.assertRaises(EOFError):
352 while zipopen.read(100):
353 pass
354
355 fp = io.BytesIO(zipfiledata)
356 with zipfile.ZipFile(fp) as zipf:
357 with zipf.open('strfile') as zipopen:
358 fp.truncate(end_offset - 20)
359 with self.assertRaises(EOFError):
360 while zipopen.read1(100):
361 pass
362
Serhiy Storchaka51a43702014-10-29 22:42:06 +0200363 def test_repr(self):
364 fname = 'file.name'
365 for f in get_files(self):
366 with zipfile.ZipFile(f, 'w', self.compression) as zipfp:
367 zipfp.write(TESTFN, fname)
368 r = repr(zipfp)
369 self.assertIn("mode='w'", r)
370
371 with zipfile.ZipFile(f, 'r') as zipfp:
372 r = repr(zipfp)
373 if isinstance(f, str):
374 self.assertIn('filename=%r' % f, r)
375 else:
376 self.assertIn('file=%r' % f, r)
377 self.assertIn("mode='r'", r)
378 r = repr(zipfp.getinfo(fname))
379 self.assertIn('filename=%r' % fname, r)
380 self.assertIn('filemode=', r)
381 self.assertIn('file_size=', r)
382 if self.compression != zipfile.ZIP_STORED:
383 self.assertIn('compress_type=', r)
384 self.assertIn('compress_size=', r)
385 with zipfp.open(fname) as zipopen:
386 r = repr(zipopen)
387 self.assertIn('name=%r' % fname, r)
388 self.assertIn("mode='r'", r)
389 if self.compression != zipfile.ZIP_STORED:
390 self.assertIn('compress_type=', r)
391 self.assertIn('[closed]', repr(zipopen))
392 self.assertIn('[closed]', repr(zipfp))
393
Bo Baylesce237c72018-01-29 23:54:07 -0600394 def test_compresslevel_basic(self):
395 for f in get_files(self):
396 self.zip_test(f, self.compression, compresslevel=9)
397
398 def test_per_file_compresslevel(self):
399 """Check that files within a Zip archive can have different
400 compression levels."""
401 with zipfile.ZipFile(TESTFN2, "w", compresslevel=1) as zipfp:
402 zipfp.write(TESTFN, 'compress_1')
403 zipfp.write(TESTFN, 'compress_9', compresslevel=9)
404 one_info = zipfp.getinfo('compress_1')
405 nine_info = zipfp.getinfo('compress_9')
406 self.assertEqual(one_info._compresslevel, 1)
407 self.assertEqual(nine_info._compresslevel, 9)
408
Serhiy Storchaka2524fde2019-03-30 08:25:19 +0200409 def test_writing_errors(self):
410 class BrokenFile(io.BytesIO):
411 def write(self, data):
412 nonlocal count
413 if count is not None:
414 if count == stop:
415 raise OSError
416 count += 1
417 super().write(data)
418
419 stop = 0
420 while True:
421 testfile = BrokenFile()
422 count = None
423 with zipfile.ZipFile(testfile, 'w', self.compression) as zipfp:
424 with zipfp.open('file1', 'w') as f:
425 f.write(b'data1')
426 count = 0
427 try:
428 with zipfp.open('file2', 'w') as f:
429 f.write(b'data2')
430 except OSError:
431 stop += 1
432 else:
433 break
434 finally:
435 count = None
436 with zipfile.ZipFile(io.BytesIO(testfile.getvalue())) as zipfp:
437 self.assertEqual(zipfp.namelist(), ['file1'])
438 self.assertEqual(zipfp.read('file1'), b'data1')
439
440 with zipfile.ZipFile(io.BytesIO(testfile.getvalue())) as zipfp:
441 self.assertEqual(zipfp.namelist(), ['file1', 'file2'])
442 self.assertEqual(zipfp.read('file1'), b'data1')
443 self.assertEqual(zipfp.read('file2'), b'data2')
444
445
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300446 def tearDown(self):
447 unlink(TESTFN)
448 unlink(TESTFN2)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200449
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200450
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300451class StoredTestsWithSourceFile(AbstractTestsWithSourceFile,
452 unittest.TestCase):
453 compression = zipfile.ZIP_STORED
454 test_low_compression = None
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200455
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300456 def zip_test_writestr_permissions(self, f, compression):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300457 # Make sure that writestr and open(... mode='w') create files with
458 # mode 0600, when they are passed a name rather than a ZipInfo
459 # instance.
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200460
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300461 self.make_test_archive(f, compression)
462 with zipfile.ZipFile(f, "r") as zipfp:
463 zinfo = zipfp.getinfo('strfile')
464 self.assertEqual(zinfo.external_attr, 0o600 << 16)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200465
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300466 zinfo2 = zipfp.getinfo('written-open-w')
467 self.assertEqual(zinfo2.external_attr, 0o600 << 16)
468
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300469 def test_writestr_permissions(self):
470 for f in get_files(self):
471 self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +0200472
Ezio Melottiafd0d112009-07-15 17:17:17 +0000473 def test_absolute_arcnames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000474 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
475 zipfp.write(TESTFN, "/absolute")
Georg Brandl8f7c54e2006-02-20 08:40:38 +0000476
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000477 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
478 self.assertEqual(zipfp.namelist(), ["absolute"])
Tim Peters32cbc962006-02-20 21:42:18 +0000479
Ezio Melottiafd0d112009-07-15 17:17:17 +0000480 def test_append_to_zip_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000481 """Test appending to an existing zipfile."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000482 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
483 zipfp.write(TESTFN, TESTFN)
484
485 with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
486 zipfp.writestr("strfile", self.data)
487 self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000488
Ezio Melottiafd0d112009-07-15 17:17:17 +0000489 def test_append_to_non_zip_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000490 """Test appending to an existing file that is not a zipfile."""
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000491 # NOTE: this test fails if len(d) < 22 because of the first
492 # line "fpin.seek(-22, 2)" in _EndRecData
Ezio Melotti35386712009-12-31 13:22:41 +0000493 data = b'I am not a ZipFile!'*10
494 with open(TESTFN2, 'wb') as f:
495 f.write(data)
496
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000497 with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
498 zipfp.write(TESTFN, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000499
Ezio Melotti35386712009-12-31 13:22:41 +0000500 with open(TESTFN2, 'rb') as f:
501 f.seek(len(data))
502 with zipfile.ZipFile(f, "r") as zipfp:
503 self.assertEqual(zipfp.namelist(), [TESTFN])
Serhiy Storchaka8793b212016-10-07 22:20:50 +0300504 self.assertEqual(zipfp.read(TESTFN), self.data)
505 with open(TESTFN2, 'rb') as f:
506 self.assertEqual(f.read(len(data)), data)
507 zipfiledata = f.read()
508 with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp:
509 self.assertEqual(zipfp.namelist(), [TESTFN])
510 self.assertEqual(zipfp.read(TESTFN), self.data)
511
512 def test_read_concatenated_zip_file(self):
513 with io.BytesIO() as bio:
514 with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp:
515 zipfp.write(TESTFN, TESTFN)
516 zipfiledata = bio.getvalue()
517 data = b'I am not a ZipFile!'*10
518 with open(TESTFN2, 'wb') as f:
519 f.write(data)
520 f.write(zipfiledata)
521
522 with zipfile.ZipFile(TESTFN2) as zipfp:
523 self.assertEqual(zipfp.namelist(), [TESTFN])
524 self.assertEqual(zipfp.read(TESTFN), self.data)
525
526 def test_append_to_concatenated_zip_file(self):
527 with io.BytesIO() as bio:
528 with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp:
529 zipfp.write(TESTFN, TESTFN)
530 zipfiledata = bio.getvalue()
531 data = b'I am not a ZipFile!'*1000000
532 with open(TESTFN2, 'wb') as f:
533 f.write(data)
534 f.write(zipfiledata)
535
536 with zipfile.ZipFile(TESTFN2, 'a') as zipfp:
537 self.assertEqual(zipfp.namelist(), [TESTFN])
538 zipfp.writestr('strfile', self.data)
539
540 with open(TESTFN2, 'rb') as f:
541 self.assertEqual(f.read(len(data)), data)
542 zipfiledata = f.read()
543 with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp:
544 self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile'])
545 self.assertEqual(zipfp.read(TESTFN), self.data)
546 self.assertEqual(zipfp.read('strfile'), self.data)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000547
R David Murray4fbb9db2011-06-09 15:50:51 -0400548 def test_ignores_newline_at_end(self):
549 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
550 zipfp.write(TESTFN, TESTFN)
551 with open(TESTFN2, 'a') as f:
552 f.write("\r\n\00\00\00")
553 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
554 self.assertIsInstance(zipfp, zipfile.ZipFile)
555
556 def test_ignores_stuff_appended_past_comments(self):
557 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
558 zipfp.comment = b"this is a comment"
559 zipfp.write(TESTFN, TESTFN)
560 with open(TESTFN2, 'a') as f:
561 f.write("abcdef\r\n")
562 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
563 self.assertIsInstance(zipfp, zipfile.ZipFile)
564 self.assertEqual(zipfp.comment, b"this is a comment")
565
Ezio Melottiafd0d112009-07-15 17:17:17 +0000566 def test_write_default_name(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000567 """Check that calling ZipFile.write without arcname specified
568 produces the expected result."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000569 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
570 zipfp.write(TESTFN)
Brian Curtin8fb9b862010-11-18 02:15:28 +0000571 with open(TESTFN, "rb") as f:
572 self.assertEqual(zipfp.read(TESTFN), f.read())
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000573
Daniel Hillier8d62df62019-11-30 19:30:47 +1100574 def test_io_on_closed_zipextfile(self):
575 fname = "somefile.txt"
576 with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
577 zipfp.writestr(fname, "bogus")
578
579 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
580 with zipfp.open(fname) as fid:
581 fid.close()
582 self.assertRaises(ValueError, fid.read)
583 self.assertRaises(ValueError, fid.seek, 0)
584 self.assertRaises(ValueError, fid.tell)
585 self.assertRaises(ValueError, fid.readable)
586 self.assertRaises(ValueError, fid.seekable)
587
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300588 def test_write_to_readonly(self):
589 """Check that trying to call write() on a readonly ZipFile object
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300590 raises a ValueError."""
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300591 with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
592 zipfp.writestr("somefile.txt", "bogus")
593
594 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300595 self.assertRaises(ValueError, zipfp.write, TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300596
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300597 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300598 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300599 zipfp.open(TESTFN, mode='w')
600
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300601 def test_add_file_before_1980(self):
602 # Set atime and mtime to 1970-01-01
603 os.utime(TESTFN, (0, 0))
604 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
605 self.assertRaises(ValueError, zipfp.write, TESTFN)
606
Marcel Plch77b112c2018-08-31 16:43:31 +0200607 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
608 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200609 zinfo = zipfp.getinfo(TESTFN)
610 self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0))
611
612 def test_add_file_after_2107(self):
613 # Set atime and mtime to 2108-12-30
Victor Stinnerc232c912020-01-30 15:47:53 +0100614 ts = 4386268800
Marcel Plch7b41dba2018-08-03 17:59:19 +0200615 try:
Victor Stinnerc232c912020-01-30 15:47:53 +0100616 time.localtime(ts)
617 except OverflowError:
618 self.skipTest(f'time.localtime({ts}) raises OverflowError')
619 try:
620 os.utime(TESTFN, (ts, ts))
Marcel Plch7b41dba2018-08-03 17:59:19 +0200621 except OverflowError:
622 self.skipTest('Host fs cannot set timestamp to required value.')
623
Victor Stinner3cb49b62020-01-29 15:23:29 +0100624 mtime_ns = os.stat(TESTFN).st_mtime_ns
625 if mtime_ns != (4386268800 * 10**9):
626 # XFS filesystem is limited to 32-bit timestamp, but the syscall
627 # didn't fail. Moreover, there is a VFS bug which returns
628 # a cached timestamp which is different than the value on disk.
629 #
630 # Test st_mtime_ns rather than st_mtime to avoid rounding issues.
631 #
632 # https://bugzilla.redhat.com/show_bug.cgi?id=1795576
633 # https://bugs.python.org/issue39460#msg360952
634 self.skipTest(f"Linux VFS/XFS kernel bug detected: {mtime_ns=}")
635
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200636 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
637 self.assertRaises(struct.error, zipfp.write, TESTFN)
638
Marcel Plch77b112c2018-08-31 16:43:31 +0200639 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
640 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200641 zinfo = zipfp.getinfo(TESTFN)
642 self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
643
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200644
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300645@requires_zlib
646class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,
647 unittest.TestCase):
648 compression = zipfile.ZIP_DEFLATED
649
Ezio Melottiafd0d112009-07-15 17:17:17 +0000650 def test_per_file_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000651 """Check that files within a Zip archive can have different
652 compression options."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000653 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
654 zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
655 zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
656 sinfo = zipfp.getinfo('storeme')
657 dinfo = zipfp.getinfo('deflateme')
658 self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
659 self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000660
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300661@requires_bz2
662class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile,
663 unittest.TestCase):
664 compression = zipfile.ZIP_BZIP2
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000665
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300666@requires_lzma
667class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile,
668 unittest.TestCase):
669 compression = zipfile.ZIP_LZMA
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000670
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300671
672class AbstractTestZip64InSmallFiles:
673 # These tests test the ZIP64 functionality without using large files,
674 # see test_zipfile64 for proper tests.
675
676 @classmethod
677 def setUpClass(cls):
678 line_gen = (bytes("Test of zipfile line %d." % i, "ascii")
679 for i in range(0, FIXEDTEST_SIZE))
680 cls.data = b'\n'.join(line_gen)
681
682 def setUp(self):
683 self._limit = zipfile.ZIP64_LIMIT
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300684 self._filecount_limit = zipfile.ZIP_FILECOUNT_LIMIT
685 zipfile.ZIP64_LIMIT = 1000
686 zipfile.ZIP_FILECOUNT_LIMIT = 9
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300687
688 # Make a source file with some lines
689 with open(TESTFN, "wb") as fp:
690 fp.write(self.data)
691
692 def zip_test(self, f, compression):
693 # Create the ZIP archive
694 with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
695 zipfp.write(TESTFN, "another.name")
696 zipfp.write(TESTFN, TESTFN)
697 zipfp.writestr("strfile", self.data)
698
699 # Read the ZIP archive
700 with zipfile.ZipFile(f, "r", compression) as zipfp:
701 self.assertEqual(zipfp.read(TESTFN), self.data)
702 self.assertEqual(zipfp.read("another.name"), self.data)
703 self.assertEqual(zipfp.read("strfile"), self.data)
704
705 # Print the ZIP directory
706 fp = io.StringIO()
707 zipfp.printdir(fp)
708
709 directory = fp.getvalue()
710 lines = directory.splitlines()
711 self.assertEqual(len(lines), 4) # Number of files + header
712
713 self.assertIn('File Name', lines[0])
714 self.assertIn('Modified', lines[0])
715 self.assertIn('Size', lines[0])
716
717 fn, date, time_, size = lines[1].split()
718 self.assertEqual(fn, 'another.name')
719 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
720 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
721 self.assertEqual(size, str(len(self.data)))
722
723 # Check the namelist
724 names = zipfp.namelist()
725 self.assertEqual(len(names), 3)
726 self.assertIn(TESTFN, names)
727 self.assertIn("another.name", names)
728 self.assertIn("strfile", names)
729
730 # Check infolist
731 infos = zipfp.infolist()
732 names = [i.filename for i in infos]
733 self.assertEqual(len(names), 3)
734 self.assertIn(TESTFN, names)
735 self.assertIn("another.name", names)
736 self.assertIn("strfile", names)
737 for i in infos:
738 self.assertEqual(i.file_size, len(self.data))
739
740 # check getinfo
741 for nm in (TESTFN, "another.name", "strfile"):
742 info = zipfp.getinfo(nm)
743 self.assertEqual(info.filename, nm)
744 self.assertEqual(info.file_size, len(self.data))
745
746 # Check that testzip doesn't raise an exception
747 zipfp.testzip()
748
749 def test_basic(self):
750 for f in get_files(self):
751 self.zip_test(f, self.compression)
752
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300753 def test_too_many_files(self):
754 # This test checks that more than 64k files can be added to an archive,
755 # and that the resulting archive can be read properly by ZipFile
756 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
757 allowZip64=True)
758 zipf.debug = 100
759 numfiles = 15
760 for i in range(numfiles):
761 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
762 self.assertEqual(len(zipf.namelist()), numfiles)
763 zipf.close()
764
765 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
766 self.assertEqual(len(zipf2.namelist()), numfiles)
767 for i in range(numfiles):
768 content = zipf2.read("foo%08d" % i).decode('ascii')
769 self.assertEqual(content, "%d" % (i**3 % 57))
770 zipf2.close()
771
772 def test_too_many_files_append(self):
773 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
774 allowZip64=False)
775 zipf.debug = 100
776 numfiles = 9
777 for i in range(numfiles):
778 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
779 self.assertEqual(len(zipf.namelist()), numfiles)
780 with self.assertRaises(zipfile.LargeZipFile):
781 zipf.writestr("foo%08d" % numfiles, b'')
782 self.assertEqual(len(zipf.namelist()), numfiles)
783 zipf.close()
784
785 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
786 allowZip64=False)
787 zipf.debug = 100
788 self.assertEqual(len(zipf.namelist()), numfiles)
789 with self.assertRaises(zipfile.LargeZipFile):
790 zipf.writestr("foo%08d" % numfiles, b'')
791 self.assertEqual(len(zipf.namelist()), numfiles)
792 zipf.close()
793
794 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
795 allowZip64=True)
796 zipf.debug = 100
797 self.assertEqual(len(zipf.namelist()), numfiles)
798 numfiles2 = 15
799 for i in range(numfiles, numfiles2):
800 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
801 self.assertEqual(len(zipf.namelist()), numfiles2)
802 zipf.close()
803
804 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
805 self.assertEqual(len(zipf2.namelist()), numfiles2)
806 for i in range(numfiles2):
807 content = zipf2.read("foo%08d" % i).decode('ascii')
808 self.assertEqual(content, "%d" % (i**3 % 57))
809 zipf2.close()
810
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300811 def tearDown(self):
812 zipfile.ZIP64_LIMIT = self._limit
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300813 zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300814 unlink(TESTFN)
815 unlink(TESTFN2)
816
817
818class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
819 unittest.TestCase):
820 compression = zipfile.ZIP_STORED
821
822 def large_file_exception_test(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200823 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300824 self.assertRaises(zipfile.LargeZipFile,
825 zipfp.write, TESTFN, "another.name")
826
827 def large_file_exception_test2(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200828 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300829 self.assertRaises(zipfile.LargeZipFile,
830 zipfp.writestr, "another.name", self.data)
831
832 def test_large_file_exception(self):
833 for f in get_files(self):
834 self.large_file_exception_test(f, zipfile.ZIP_STORED)
835 self.large_file_exception_test2(f, zipfile.ZIP_STORED)
836
837 def test_absolute_arcnames(self):
838 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
839 allowZip64=True) as zipfp:
840 zipfp.write(TESTFN, "/absolute")
841
842 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
843 self.assertEqual(zipfp.namelist(), ["absolute"])
844
Serhiy Storchaka9bdb7be2018-09-17 15:36:40 +0300845 def test_append(self):
846 # Test that appending to the Zip64 archive doesn't change
847 # extra fields of existing entries.
848 with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp:
849 zipfp.writestr("strfile", self.data)
850 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
851 zinfo = zipfp.getinfo("strfile")
852 extra = zinfo.extra
853 with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp:
854 zipfp.writestr("strfile2", self.data)
855 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
856 zinfo = zipfp.getinfo("strfile")
857 self.assertEqual(zinfo.extra, extra)
858
Daniel Hillierda6ce582019-10-29 18:24:18 +1100859 def make_zip64_file(
860 self, file_size_64_set=False, file_size_extra=False,
861 compress_size_64_set=False, compress_size_extra=False,
862 header_offset_64_set=False, header_offset_extra=False,
863 ):
864 """Generate bytes sequence for a zip with (incomplete) zip64 data.
865
866 The actual values (not the zip 64 0xffffffff values) stored in the file
867 are:
868 file_size: 8
869 compress_size: 8
870 header_offset: 0
871 """
872 actual_size = 8
873 actual_header_offset = 0
874 local_zip64_fields = []
875 central_zip64_fields = []
876
877 file_size = actual_size
878 if file_size_64_set:
879 file_size = 0xffffffff
880 if file_size_extra:
881 local_zip64_fields.append(actual_size)
882 central_zip64_fields.append(actual_size)
883 file_size = struct.pack("<L", file_size)
884
885 compress_size = actual_size
886 if compress_size_64_set:
887 compress_size = 0xffffffff
888 if compress_size_extra:
889 local_zip64_fields.append(actual_size)
890 central_zip64_fields.append(actual_size)
891 compress_size = struct.pack("<L", compress_size)
892
893 header_offset = actual_header_offset
894 if header_offset_64_set:
895 header_offset = 0xffffffff
896 if header_offset_extra:
897 central_zip64_fields.append(actual_header_offset)
898 header_offset = struct.pack("<L", header_offset)
899
900 local_extra = struct.pack(
901 '<HH' + 'Q'*len(local_zip64_fields),
902 0x0001,
903 8*len(local_zip64_fields),
904 *local_zip64_fields
905 )
906
907 central_extra = struct.pack(
908 '<HH' + 'Q'*len(central_zip64_fields),
909 0x0001,
910 8*len(central_zip64_fields),
911 *central_zip64_fields
912 )
913
914 central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
915 offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
916
917 local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
918 central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
919
920 filename = b"test.txt"
921 content = b"test1234"
922 filename_length = struct.pack("<H", len(filename))
923 zip64_contents = (
924 # Local file header
925 b"PK\x03\x04\x14\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
926 + compress_size
927 + file_size
928 + filename_length
929 + local_extra_length
930 + filename
931 + local_extra
932 + content
933 # Central directory:
934 + b"PK\x01\x02-\x03-\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
935 + compress_size
936 + file_size
937 + filename_length
938 + central_extra_length
939 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01"
940 + header_offset
941 + filename
942 + central_extra
943 # Zip64 end of central directory
944 + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
945 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
946 + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
947 + central_dir_size
948 + offset_to_central_dir
949 # Zip64 end of central directory locator
950 + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
951 + b"\x00\x00\x00"
952 # end of central directory
953 + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
954 + b"\x00\x00\x00\x00"
955 )
956 return zip64_contents
957
958 def test_bad_zip64_extra(self):
959 """Missing zip64 extra records raises an exception.
960
961 There are 4 fields that the zip64 format handles (the disk number is
962 not used in this module and so is ignored here). According to the zip
963 spec:
964 The order of the fields in the zip64 extended
965 information record is fixed, but the fields MUST
966 only appear if the corresponding Local or Central
967 directory record field is set to 0xFFFF or 0xFFFFFFFF.
968
969 If the zip64 extra content doesn't contain enough entries for the
970 number of fields marked with 0xFFFF or 0xFFFFFFFF, we raise an error.
971 This test mismatches the length of the zip64 extra field and the number
972 of fields set to indicate the presence of zip64 data.
973 """
974 # zip64 file size present, no fields in extra, expecting one, equals
975 # missing file size.
976 missing_file_size_extra = self.make_zip64_file(
977 file_size_64_set=True,
978 )
979 with self.assertRaises(zipfile.BadZipFile) as e:
980 zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
981 self.assertIn('file size', str(e.exception).lower())
982
983 # zip64 file size present, zip64 compress size present, one field in
984 # extra, expecting two, equals missing compress size.
985 missing_compress_size_extra = self.make_zip64_file(
986 file_size_64_set=True,
987 file_size_extra=True,
988 compress_size_64_set=True,
989 )
990 with self.assertRaises(zipfile.BadZipFile) as e:
991 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
992 self.assertIn('compress size', str(e.exception).lower())
993
994 # zip64 compress size present, no fields in extra, expecting one,
995 # equals missing compress size.
996 missing_compress_size_extra = self.make_zip64_file(
997 compress_size_64_set=True,
998 )
999 with self.assertRaises(zipfile.BadZipFile) as e:
1000 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
1001 self.assertIn('compress size', str(e.exception).lower())
1002
1003 # zip64 file size present, zip64 compress size present, zip64 header
1004 # offset present, two fields in extra, expecting three, equals missing
1005 # header offset
1006 missing_header_offset_extra = self.make_zip64_file(
1007 file_size_64_set=True,
1008 file_size_extra=True,
1009 compress_size_64_set=True,
1010 compress_size_extra=True,
1011 header_offset_64_set=True,
1012 )
1013 with self.assertRaises(zipfile.BadZipFile) as e:
1014 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1015 self.assertIn('header offset', str(e.exception).lower())
1016
1017 # zip64 compress size present, zip64 header offset present, one field
1018 # in extra, expecting two, equals missing header offset
1019 missing_header_offset_extra = self.make_zip64_file(
1020 file_size_64_set=False,
1021 compress_size_64_set=True,
1022 compress_size_extra=True,
1023 header_offset_64_set=True,
1024 )
1025 with self.assertRaises(zipfile.BadZipFile) as e:
1026 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1027 self.assertIn('header offset', str(e.exception).lower())
1028
1029 # zip64 file size present, zip64 header offset present, one field in
1030 # extra, expecting two, equals missing header offset
1031 missing_header_offset_extra = self.make_zip64_file(
1032 file_size_64_set=True,
1033 file_size_extra=True,
1034 compress_size_64_set=False,
1035 header_offset_64_set=True,
1036 )
1037 with self.assertRaises(zipfile.BadZipFile) as e:
1038 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1039 self.assertIn('header offset', str(e.exception).lower())
1040
1041 # zip64 header offset present, no fields in extra, expecting one,
1042 # equals missing header offset
1043 missing_header_offset_extra = self.make_zip64_file(
1044 file_size_64_set=False,
1045 compress_size_64_set=False,
1046 header_offset_64_set=True,
1047 )
1048 with self.assertRaises(zipfile.BadZipFile) as e:
1049 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1050 self.assertIn('header offset', str(e.exception).lower())
1051
1052 def test_generated_valid_zip64_extra(self):
1053 # These values are what is set in the make_zip64_file method.
1054 expected_file_size = 8
1055 expected_compress_size = 8
1056 expected_header_offset = 0
1057 expected_content = b"test1234"
1058
1059 # Loop through the various valid combinations of zip64 masks
1060 # present and extra fields present.
1061 params = (
1062 {"file_size_64_set": True, "file_size_extra": True},
1063 {"compress_size_64_set": True, "compress_size_extra": True},
1064 {"header_offset_64_set": True, "header_offset_extra": True},
1065 )
1066
1067 for r in range(1, len(params) + 1):
1068 for combo in itertools.combinations(params, r):
1069 kwargs = {}
1070 for c in combo:
1071 kwargs.update(c)
1072 with zipfile.ZipFile(io.BytesIO(self.make_zip64_file(**kwargs))) as zf:
1073 zinfo = zf.infolist()[0]
1074 self.assertEqual(zinfo.file_size, expected_file_size)
1075 self.assertEqual(zinfo.compress_size, expected_compress_size)
1076 self.assertEqual(zinfo.header_offset, expected_header_offset)
1077 self.assertEqual(zf.read(zinfo), expected_content)
1078
1079
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001080@requires_zlib
1081class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1082 unittest.TestCase):
1083 compression = zipfile.ZIP_DEFLATED
1084
1085@requires_bz2
1086class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1087 unittest.TestCase):
1088 compression = zipfile.ZIP_BZIP2
1089
1090@requires_lzma
1091class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1092 unittest.TestCase):
1093 compression = zipfile.ZIP_LZMA
1094
1095
Serhiy Storchaka4c0d9ea2017-04-12 16:03:23 +03001096class AbstractWriterTests:
1097
1098 def tearDown(self):
1099 unlink(TESTFN2)
1100
1101 def test_close_after_close(self):
1102 data = b'content'
1103 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1104 w = zipf.open('test', 'w')
1105 w.write(data)
1106 w.close()
1107 self.assertTrue(w.closed)
1108 w.close()
1109 self.assertTrue(w.closed)
1110 self.assertEqual(zipf.read('test'), data)
1111
1112 def test_write_after_close(self):
1113 data = b'content'
1114 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1115 w = zipf.open('test', 'w')
1116 w.write(data)
1117 w.close()
1118 self.assertTrue(w.closed)
1119 self.assertRaises(ValueError, w.write, b'')
1120 self.assertEqual(zipf.read('test'), data)
1121
1122class StoredWriterTests(AbstractWriterTests, unittest.TestCase):
1123 compression = zipfile.ZIP_STORED
1124
1125@requires_zlib
1126class DeflateWriterTests(AbstractWriterTests, unittest.TestCase):
1127 compression = zipfile.ZIP_DEFLATED
1128
1129@requires_bz2
1130class Bzip2WriterTests(AbstractWriterTests, unittest.TestCase):
1131 compression = zipfile.ZIP_BZIP2
1132
1133@requires_lzma
1134class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
1135 compression = zipfile.ZIP_LZMA
1136
1137
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001138class PyZipFileTests(unittest.TestCase):
1139 def assertCompiledIn(self, name, namelist):
1140 if name + 'o' not in namelist:
1141 self.assertIn(name + 'c', namelist)
1142
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001143 def requiresWriteAccess(self, path):
Berker Peksage1efc072015-02-16 04:36:18 +02001144 # effective_ids unavailable on windows
1145 if not os.access(path, os.W_OK,
1146 effective_ids=os.access in os.supports_effective_ids):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001147 self.skipTest('requires write access to the installed location')
Serhiy Storchakad86a6ef2015-09-19 10:55:20 +03001148 filename = os.path.join(path, 'test_zipfile.try')
1149 try:
1150 fd = os.open(filename, os.O_WRONLY | os.O_CREAT)
1151 os.close(fd)
1152 except Exception:
1153 self.skipTest('requires write access to the installed location')
1154 unlink(filename)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001155
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001156 def test_write_pyfile(self):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001157 self.requiresWriteAccess(os.path.dirname(__file__))
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001158 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1159 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001160 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001161 path_split = fn.split(os.sep)
1162 if os.altsep is not None:
1163 path_split.extend(fn.split(os.altsep))
1164 if '__pycache__' in path_split:
Serhiy Storchaka9068e4d2013-07-22 21:02:14 +03001165 fn = importlib.util.source_from_cache(fn)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001166 else:
1167 fn = fn[:-1]
1168
1169 zipfp.writepy(fn)
1170
1171 bn = os.path.basename(fn)
1172 self.assertNotIn(bn, zipfp.namelist())
1173 self.assertCompiledIn(bn, zipfp.namelist())
1174
1175 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1176 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001177 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001178 fn = fn[:-1]
1179
1180 zipfp.writepy(fn, "testpackage")
1181
1182 bn = "%s/%s" % ("testpackage", os.path.basename(fn))
1183 self.assertNotIn(bn, zipfp.namelist())
1184 self.assertCompiledIn(bn, zipfp.namelist())
1185
1186 def test_write_python_package(self):
1187 import email
1188 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001189 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001190
1191 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1192 zipfp.writepy(packagedir)
1193
1194 # Check for a couple of modules at different levels of the
1195 # hierarchy
1196 names = zipfp.namelist()
1197 self.assertCompiledIn('email/__init__.py', names)
1198 self.assertCompiledIn('email/mime/text.py', names)
1199
Christian Tismer59202e52013-10-21 03:59:23 +02001200 def test_write_filtered_python_package(self):
1201 import test
1202 packagedir = os.path.dirname(test.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001203 self.requiresWriteAccess(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001204
1205 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1206
Christian Tismer59202e52013-10-21 03:59:23 +02001207 # first make sure that the test folder gives error messages
Georg Brandla6065422013-10-21 08:29:29 +02001208 # (on the badsyntax_... files)
1209 with captured_stdout() as reportSIO:
1210 zipfp.writepy(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001211 reportStr = reportSIO.getvalue()
1212 self.assertTrue('SyntaxError' in reportStr)
1213
Christian Tismer410d9312013-10-22 04:09:28 +02001214 # then check that the filter works on the whole package
Georg Brandla6065422013-10-21 08:29:29 +02001215 with captured_stdout() as reportSIO:
1216 zipfp.writepy(packagedir, filterfunc=lambda whatever: False)
Christian Tismer59202e52013-10-21 03:59:23 +02001217 reportStr = reportSIO.getvalue()
1218 self.assertTrue('SyntaxError' not in reportStr)
1219
Christian Tismer410d9312013-10-22 04:09:28 +02001220 # then check that the filter works on individual files
Larry Hastings7e63b362015-05-08 06:54:58 -07001221 def filter(path):
1222 return not os.path.basename(path).startswith("bad")
Serhiy Storchakac46d1fa2014-01-20 21:59:33 +02001223 with captured_stdout() as reportSIO, self.assertWarns(UserWarning):
Larry Hastings7e63b362015-05-08 06:54:58 -07001224 zipfp.writepy(packagedir, filterfunc=filter)
Christian Tismer410d9312013-10-22 04:09:28 +02001225 reportStr = reportSIO.getvalue()
1226 if reportStr:
1227 print(reportStr)
1228 self.assertTrue('SyntaxError' not in reportStr)
1229
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001230 def test_write_with_optimization(self):
1231 import email
1232 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001233 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001234 optlevel = 1 if __debug__ else 0
Brett Cannonf299abd2015-04-13 14:21:02 -04001235 ext = '.pyc'
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001236
1237 with TemporaryFile() as t, \
Christian Tismer59202e52013-10-21 03:59:23 +02001238 zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001239 zipfp.writepy(packagedir)
1240
1241 names = zipfp.namelist()
1242 self.assertIn('email/__init__' + ext, names)
1243 self.assertIn('email/mime/text' + ext, names)
1244
1245 def test_write_python_directory(self):
1246 os.mkdir(TESTFN2)
1247 try:
1248 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1249 fp.write("print(42)\n")
1250
1251 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1252 fp.write("print(42 * 42)\n")
1253
1254 with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp:
1255 fp.write("bla bla bla\n")
1256
1257 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1258 zipfp.writepy(TESTFN2)
1259
1260 names = zipfp.namelist()
1261 self.assertCompiledIn('mod1.py', names)
1262 self.assertCompiledIn('mod2.py', names)
1263 self.assertNotIn('mod2.txt', names)
1264
1265 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001266 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001267
Christian Tismer410d9312013-10-22 04:09:28 +02001268 def test_write_python_directory_filtered(self):
1269 os.mkdir(TESTFN2)
1270 try:
1271 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1272 fp.write("print(42)\n")
1273
1274 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1275 fp.write("print(42 * 42)\n")
1276
1277 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1278 zipfp.writepy(TESTFN2, filterfunc=lambda fn:
1279 not fn.endswith('mod2.py'))
1280
1281 names = zipfp.namelist()
1282 self.assertCompiledIn('mod1.py', names)
1283 self.assertNotIn('mod2.py', names)
1284
1285 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001286 rmtree(TESTFN2)
Christian Tismer410d9312013-10-22 04:09:28 +02001287
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001288 def test_write_non_pyfile(self):
1289 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1290 with open(TESTFN, 'w') as f:
1291 f.write('most definitely not a python file')
1292 self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
Victor Stinner88b215e2014-09-04 00:51:09 +02001293 unlink(TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001294
1295 def test_write_pyfile_bad_syntax(self):
1296 os.mkdir(TESTFN2)
1297 try:
1298 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1299 fp.write("Bad syntax in python file\n")
1300
1301 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1302 # syntax errors are printed to stdout
1303 with captured_stdout() as s:
1304 zipfp.writepy(os.path.join(TESTFN2, "mod1.py"))
1305
1306 self.assertIn("SyntaxError", s.getvalue())
1307
1308 # as it will not have compiled the python file, it will
Brett Cannonf299abd2015-04-13 14:21:02 -04001309 # include the .py file not .pyc
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001310 names = zipfp.namelist()
1311 self.assertIn('mod1.py', names)
1312 self.assertNotIn('mod1.pyc', names)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001313
1314 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001315 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001316
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001317 def test_write_pathlike(self):
1318 os.mkdir(TESTFN2)
1319 try:
1320 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1321 fp.write("print(42)\n")
1322
1323 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1324 zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py")
1325 names = zipfp.namelist()
1326 self.assertCompiledIn('mod1.py', names)
1327 finally:
1328 rmtree(TESTFN2)
1329
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001330
1331class ExtractTests(unittest.TestCase):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001332
1333 def make_test_file(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001334 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1335 for fpath, fdata in SMALL_TEST_DATA:
1336 zipfp.writestr(fpath, fdata)
Christian Heimes790c8232008-01-07 21:14:23 +00001337
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001338 def test_extract(self):
1339 with temp_cwd():
1340 self.make_test_file()
1341 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1342 for fpath, fdata in SMALL_TEST_DATA:
1343 writtenfile = zipfp.extract(fpath)
1344
1345 # make sure it was written to the right place
1346 correctfile = os.path.join(os.getcwd(), fpath)
1347 correctfile = os.path.normpath(correctfile)
1348
1349 self.assertEqual(writtenfile, correctfile)
1350
1351 # make sure correct data is in correct file
1352 with open(writtenfile, "rb") as f:
1353 self.assertEqual(fdata.encode(), f.read())
1354
1355 unlink(writtenfile)
1356
1357 def _test_extract_with_target(self, target):
1358 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001359 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1360 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001361 writtenfile = zipfp.extract(fpath, target)
Christian Heimes790c8232008-01-07 21:14:23 +00001362
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001363 # make sure it was written to the right place
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001364 correctfile = os.path.join(target, fpath)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001365 correctfile = os.path.normpath(correctfile)
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001366 self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target))
Christian Heimes790c8232008-01-07 21:14:23 +00001367
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001368 # make sure correct data is in correct file
Brian Curtin8fb9b862010-11-18 02:15:28 +00001369 with open(writtenfile, "rb") as f:
1370 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001371
Victor Stinner88b215e2014-09-04 00:51:09 +02001372 unlink(writtenfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001373
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001374 unlink(TESTFN2)
1375
1376 def test_extract_with_target(self):
1377 with temp_dir() as extdir:
1378 self._test_extract_with_target(extdir)
1379
1380 def test_extract_with_target_pathlike(self):
1381 with temp_dir() as extdir:
1382 self._test_extract_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001383
Ezio Melottiafd0d112009-07-15 17:17:17 +00001384 def test_extract_all(self):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001385 with temp_cwd():
1386 self.make_test_file()
1387 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1388 zipfp.extractall()
1389 for fpath, fdata in SMALL_TEST_DATA:
1390 outfile = os.path.join(os.getcwd(), fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001391
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001392 with open(outfile, "rb") as f:
1393 self.assertEqual(fdata.encode(), f.read())
1394
1395 unlink(outfile)
1396
1397 def _test_extract_all_with_target(self, target):
1398 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001399 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001400 zipfp.extractall(target)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001401 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001402 outfile = os.path.join(target, fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001403
Brian Curtin8fb9b862010-11-18 02:15:28 +00001404 with open(outfile, "rb") as f:
1405 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001406
Victor Stinner88b215e2014-09-04 00:51:09 +02001407 unlink(outfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001408
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001409 unlink(TESTFN2)
1410
1411 def test_extract_all_with_target(self):
1412 with temp_dir() as extdir:
1413 self._test_extract_all_with_target(extdir)
1414
1415 def test_extract_all_with_target_pathlike(self):
1416 with temp_dir() as extdir:
1417 self._test_extract_all_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001418
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001419 def check_file(self, filename, content):
1420 self.assertTrue(os.path.isfile(filename))
1421 with open(filename, 'rb') as f:
1422 self.assertEqual(f.read(), content)
1423
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001424 def test_sanitize_windows_name(self):
1425 san = zipfile.ZipFile._sanitize_windows_name
1426 # Passing pathsep in allows this test to work regardless of platform.
1427 self.assertEqual(san(r',,?,C:,foo,bar/z', ','), r'_,C_,foo,bar/z')
1428 self.assertEqual(san(r'a\b,c<d>e|f"g?h*i', ','), r'a\b,c_d_e_f_g_h_i')
1429 self.assertEqual(san('../../foo../../ba..r', '/'), r'foo/ba..r')
1430
1431 def test_extract_hackers_arcnames_common_cases(self):
1432 common_hacknames = [
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001433 ('../foo/bar', 'foo/bar'),
1434 ('foo/../bar', 'foo/bar'),
1435 ('foo/../../bar', 'foo/bar'),
1436 ('foo/bar/..', 'foo/bar'),
1437 ('./../foo/bar', 'foo/bar'),
1438 ('/foo/bar', 'foo/bar'),
1439 ('/foo/../bar', 'foo/bar'),
1440 ('/foo/../../bar', 'foo/bar'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001441 ]
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001442 self._test_extract_hackers_arcnames(common_hacknames)
1443
1444 @unittest.skipIf(os.path.sep != '\\', 'Requires \\ as path separator.')
1445 def test_extract_hackers_arcnames_windows_only(self):
1446 """Test combination of path fixing and windows name sanitization."""
1447 windows_hacknames = [
Christian Tismer59202e52013-10-21 03:59:23 +02001448 (r'..\foo\bar', 'foo/bar'),
1449 (r'..\/foo\/bar', 'foo/bar'),
1450 (r'foo/\..\/bar', 'foo/bar'),
1451 (r'foo\/../\bar', 'foo/bar'),
1452 (r'C:foo/bar', 'foo/bar'),
1453 (r'C:/foo/bar', 'foo/bar'),
1454 (r'C://foo/bar', 'foo/bar'),
1455 (r'C:\foo\bar', 'foo/bar'),
1456 (r'//conky/mountpoint/foo/bar', 'foo/bar'),
1457 (r'\\conky\mountpoint\foo\bar', 'foo/bar'),
1458 (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1459 (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1460 (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1461 (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1462 (r'//?/C:/foo/bar', 'foo/bar'),
1463 (r'\\?\C:\foo\bar', 'foo/bar'),
1464 (r'C:/../C:/foo/bar', 'C_/foo/bar'),
1465 (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
1466 ('../../foo../../ba..r', 'foo/ba..r'),
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001467 ]
1468 self._test_extract_hackers_arcnames(windows_hacknames)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001469
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001470 @unittest.skipIf(os.path.sep != '/', r'Requires / as path separator.')
1471 def test_extract_hackers_arcnames_posix_only(self):
1472 posix_hacknames = [
1473 ('//foo/bar', 'foo/bar'),
1474 ('../../foo../../ba..r', 'foo../ba..r'),
1475 (r'foo/..\bar', r'foo/..\bar'),
1476 ]
1477 self._test_extract_hackers_arcnames(posix_hacknames)
1478
1479 def _test_extract_hackers_arcnames(self, hacknames):
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001480 for arcname, fixedname in hacknames:
1481 content = b'foobar' + arcname.encode()
1482 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001483 zinfo = zipfile.ZipInfo()
1484 # preserve backslashes
1485 zinfo.filename = arcname
1486 zinfo.external_attr = 0o600 << 16
1487 zipfp.writestr(zinfo, content)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001488
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001489 arcname = arcname.replace(os.sep, "/")
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001490 targetpath = os.path.join('target', 'subdir', 'subsub')
1491 correctfile = os.path.join(targetpath, *fixedname.split('/'))
1492
1493 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1494 writtenfile = zipfp.extract(arcname, targetpath)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001495 self.assertEqual(writtenfile, correctfile,
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001496 msg='extract %r: %r != %r' %
1497 (arcname, writtenfile, correctfile))
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001498 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001499 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001500
1501 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1502 zipfp.extractall(targetpath)
1503 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001504 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001505
1506 correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
1507
1508 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1509 writtenfile = zipfp.extract(arcname)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001510 self.assertEqual(writtenfile, correctfile,
1511 msg="extract %r" % arcname)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001512 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001513 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001514
1515 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1516 zipfp.extractall()
1517 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001518 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001519
Victor Stinner88b215e2014-09-04 00:51:09 +02001520 unlink(TESTFN2)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001521
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001522
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001523class OtherTests(unittest.TestCase):
1524 def test_open_via_zip_info(self):
1525 # Create the ZIP archive
1526 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1527 zipfp.writestr("name", "foo")
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001528 with self.assertWarns(UserWarning):
1529 zipfp.writestr("name", "bar")
1530 self.assertEqual(zipfp.namelist(), ["name"] * 2)
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001531
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001532 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1533 infos = zipfp.infolist()
1534 data = b""
1535 for info in infos:
1536 with zipfp.open(info) as zipopen:
1537 data += zipopen.read()
1538 self.assertIn(data, {b"foobar", b"barfoo"})
1539 data = b""
1540 for info in infos:
1541 data += zipfp.read(info)
1542 self.assertIn(data, {b"foobar", b"barfoo"})
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02001543
Gregory P. Smithb0d9ca92009-07-07 05:06:04 +00001544 def test_writestr_extended_local_header_issue1202(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001545 with zipfile.ZipFile(TESTFN2, 'w') as orig_zip:
1546 for data in 'abcdefghijklmnop':
1547 zinfo = zipfile.ZipInfo(data)
1548 zinfo.flag_bits |= 0x08 # Include an extended local header.
1549 orig_zip.writestr(zinfo, data)
1550
1551 def test_close(self):
1552 """Check that the zipfile is closed after the 'with' block."""
1553 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1554 for fpath, fdata in SMALL_TEST_DATA:
1555 zipfp.writestr(fpath, fdata)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001556 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1557 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001558
1559 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001560 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1561 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001562
1563 def test_close_on_exception(self):
1564 """Check that the zipfile is closed if an exception is raised in the
1565 'with' block."""
1566 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1567 for fpath, fdata in SMALL_TEST_DATA:
1568 zipfp.writestr(fpath, fdata)
1569
1570 try:
1571 with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
Georg Brandl4d540882010-10-28 06:42:33 +00001572 raise zipfile.BadZipFile()
1573 except zipfile.BadZipFile:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001574 self.assertIsNone(zipfp2.fp, 'zipfp is not closed')
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00001575
Martin v. Löwisd099b562012-05-01 14:08:22 +02001576 def test_unsupported_version(self):
1577 # File has an extract_version of 120
1578 data = (b'PK\x03\x04x\x00\x00\x00\x00\x00!p\xa1@\x00\x00\x00\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001579 b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00xPK\x01\x02x\x03x\x00\x00\x00\x00'
1580 b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
1581 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06'
1582 b'\x00\x00\x00\x00\x01\x00\x01\x00/\x00\x00\x00\x1f\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001583
Martin v. Löwisd099b562012-05-01 14:08:22 +02001584 self.assertRaises(NotImplementedError, zipfile.ZipFile,
1585 io.BytesIO(data), 'r')
1586
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001587 @requires_zlib
1588 def test_read_unicode_filenames(self):
1589 # bug #10801
1590 fname = findfile('zip_cp437_header.zip')
1591 with zipfile.ZipFile(fname) as zipfp:
1592 for name in zipfp.namelist():
1593 zipfp.open(name).close()
1594
1595 def test_write_unicode_filenames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001596 with zipfile.ZipFile(TESTFN, "w") as zf:
1597 zf.writestr("foo.txt", "Test for unicode filename")
1598 zf.writestr("\xf6.txt", "Test for unicode filename")
Ezio Melottie9615932010-01-24 19:26:24 +00001599 self.assertIsInstance(zf.infolist()[0].filename, str)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001600
1601 with zipfile.ZipFile(TESTFN, "r") as zf:
1602 self.assertEqual(zf.filelist[0].filename, "foo.txt")
1603 self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
Martin v. Löwis8570f6a2008-05-05 17:44:38 +00001604
Serhiy Storchaka764fc9b2015-03-25 10:09:41 +02001605 def test_exclusive_create_zip_file(self):
1606 """Test exclusive creating a new zipfile."""
1607 unlink(TESTFN2)
1608 filename = 'testfile.txt'
1609 content = b'hello, world. this is some content.'
1610 with zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED) as zipfp:
1611 zipfp.writestr(filename, content)
1612 with self.assertRaises(FileExistsError):
1613 zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED)
1614 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1615 self.assertEqual(zipfp.namelist(), [filename])
1616 self.assertEqual(zipfp.read(filename), content)
1617
Ezio Melottiafd0d112009-07-15 17:17:17 +00001618 def test_create_non_existent_file_for_append(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00001619 if os.path.exists(TESTFN):
1620 os.unlink(TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001621
Thomas Wouterscf297e42007-02-23 15:07:44 +00001622 filename = 'testfile.txt'
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001623 content = b'hello, world. this is some content.'
Guido van Rossumd8faa362007-04-27 19:54:29 +00001624
Thomas Wouterscf297e42007-02-23 15:07:44 +00001625 try:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001626 with zipfile.ZipFile(TESTFN, 'a') as zf:
1627 zf.writestr(filename, content)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001628 except OSError:
Thomas Wouterscf297e42007-02-23 15:07:44 +00001629 self.fail('Could not append data to a non-existent zip file.')
1630
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001631 self.assertTrue(os.path.exists(TESTFN))
Thomas Wouterscf297e42007-02-23 15:07:44 +00001632
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001633 with zipfile.ZipFile(TESTFN, 'r') as zf:
1634 self.assertEqual(zf.read(filename), content)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001635
Ezio Melottiafd0d112009-07-15 17:17:17 +00001636 def test_close_erroneous_file(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001637 # This test checks that the ZipFile constructor closes the file object
Ezio Melotti35386712009-12-31 13:22:41 +00001638 # it opens if there's an error in the file. If it doesn't, the
1639 # traceback holds a reference to the ZipFile object and, indirectly,
1640 # the file object.
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001641 # On Windows, this causes the os.unlink() call to fail because the
1642 # underlying file is still open. This is SF bug #412214.
1643 #
Ezio Melotti35386712009-12-31 13:22:41 +00001644 with open(TESTFN, "w") as fp:
1645 fp.write("this is not a legal zip file\n")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001646 try:
1647 zf = zipfile.ZipFile(TESTFN)
Georg Brandl4d540882010-10-28 06:42:33 +00001648 except zipfile.BadZipFile:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001649 pass
1650
Ezio Melottiafd0d112009-07-15 17:17:17 +00001651 def test_is_zip_erroneous_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001652 """Check that is_zipfile() correctly identifies non-zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001653 # - passing a filename
1654 with open(TESTFN, "w") as fp:
1655 fp.write("this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001656 self.assertFalse(zipfile.is_zipfile(TESTFN))
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001657 # - passing a path-like object
1658 self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN)))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001659 # - passing a file object
1660 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001661 self.assertFalse(zipfile.is_zipfile(fp))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001662 # - passing a file-like object
1663 fp = io.BytesIO()
1664 fp.write(b"this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001665 self.assertFalse(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001666 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001667 self.assertFalse(zipfile.is_zipfile(fp))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001668
Serhiy Storchakad2b15272013-01-31 15:27:07 +02001669 def test_damaged_zipfile(self):
1670 """Check that zipfiles with missing bytes at the end raise BadZipFile."""
1671 # - Create a valid zip file
1672 fp = io.BytesIO()
1673 with zipfile.ZipFile(fp, mode="w") as zipf:
1674 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1675 zipfiledata = fp.getvalue()
1676
1677 # - Now create copies of it missing the last N bytes and make sure
1678 # a BadZipFile exception is raised when we try to open it
1679 for N in range(len(zipfiledata)):
1680 fp = io.BytesIO(zipfiledata[:N])
1681 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, fp)
1682
Ezio Melottiafd0d112009-07-15 17:17:17 +00001683 def test_is_zip_valid_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001684 """Check that is_zipfile() correctly identifies zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001685 # - passing a filename
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001686 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1687 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1688
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001689 self.assertTrue(zipfile.is_zipfile(TESTFN))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001690 # - passing a file object
1691 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001692 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001693 fp.seek(0, 0)
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001694 zip_contents = fp.read()
1695 # - passing a file-like object
1696 fp = io.BytesIO()
1697 fp.write(zip_contents)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001698 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001699 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001700 self.assertTrue(zipfile.is_zipfile(fp))
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001701
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001702 def test_non_existent_file_raises_OSError(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001703 # make sure we don't raise an AttributeError when a partially-constructed
1704 # ZipFile instance is finalized; this tests for regression on SF tracker
1705 # bug #403871.
1706
1707 # The bug we're testing for caused an AttributeError to be raised
1708 # when a ZipFile instance was created for a file that did not
1709 # exist; the .fp member was not initialized but was needed by the
1710 # __del__() method. Since the AttributeError is in the __del__(),
1711 # it is ignored, but the user should be sufficiently annoyed by
1712 # the message on the output that regression will be noticed
1713 # quickly.
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001714 self.assertRaises(OSError, zipfile.ZipFile, TESTFN)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001715
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001716 def test_empty_file_raises_BadZipFile(self):
1717 f = open(TESTFN, 'w')
1718 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001719 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001720
Ezio Melotti35386712009-12-31 13:22:41 +00001721 with open(TESTFN, 'w') as fp:
1722 fp.write("short file")
Georg Brandl4d540882010-10-28 06:42:33 +00001723 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001724
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001725 def test_closed_zip_raises_ValueError(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001726 """Verify that testzip() doesn't swallow inappropriate exceptions."""
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001727 data = io.BytesIO()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001728 with zipfile.ZipFile(data, mode="w") as zipf:
1729 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001730
Andrew Svetlov737fb892012-12-18 21:14:22 +02001731 # This is correct; calling .read on a closed ZipFile should raise
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001732 # a ValueError, and so should calling .testzip. An earlier
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001733 # version of .testzip would swallow this exception (and any other)
1734 # and report that the first file in the archive was corrupt.
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001735 self.assertRaises(ValueError, zipf.read, "foo.txt")
1736 self.assertRaises(ValueError, zipf.open, "foo.txt")
1737 self.assertRaises(ValueError, zipf.testzip)
1738 self.assertRaises(ValueError, zipf.writestr, "bogus.txt", "bogus")
Brian Curtin8fb9b862010-11-18 02:15:28 +00001739 with open(TESTFN, 'w') as f:
1740 f.write('zipfile test data')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001741 self.assertRaises(ValueError, zipf.write, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001742
Ezio Melottiafd0d112009-07-15 17:17:17 +00001743 def test_bad_constructor_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001744 """Check that bad modes passed to ZipFile constructor are caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001745 self.assertRaises(ValueError, zipfile.ZipFile, TESTFN, "q")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001746
Ezio Melottiafd0d112009-07-15 17:17:17 +00001747 def test_bad_open_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001748 """Check that bad modes passed to ZipFile.open are caught."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001749 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1750 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1751
1752 with zipfile.ZipFile(TESTFN, mode="r") as zipf:
Serhiy Storchakae670be22016-06-11 19:32:44 +03001753 # read the data to make sure the file is there
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001754 zipf.read("foo.txt")
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001755 self.assertRaises(ValueError, zipf.open, "foo.txt", "q")
Serhiy Storchakae670be22016-06-11 19:32:44 +03001756 # universal newlines support is removed
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001757 self.assertRaises(ValueError, zipf.open, "foo.txt", "U")
1758 self.assertRaises(ValueError, zipf.open, "foo.txt", "rU")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001759
Ezio Melottiafd0d112009-07-15 17:17:17 +00001760 def test_read0(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001761 """Check that calling read(0) on a ZipExtFile object returns an empty
1762 string and doesn't advance file pointer."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001763 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1764 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1765 # read the data to make sure the file is there
Brian Curtin8fb9b862010-11-18 02:15:28 +00001766 with zipf.open("foo.txt") as f:
1767 for i in range(FIXEDTEST_SIZE):
1768 self.assertEqual(f.read(0), b'')
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001769
Brian Curtin8fb9b862010-11-18 02:15:28 +00001770 self.assertEqual(f.read(), b"O, for a Muse of Fire!")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001771
Ezio Melottiafd0d112009-07-15 17:17:17 +00001772 def test_open_non_existent_item(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001773 """Check that attempting to call open() for an item that doesn't
1774 exist in the archive raises a RuntimeError."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001775 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1776 self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001777
Ezio Melottiafd0d112009-07-15 17:17:17 +00001778 def test_bad_compression_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001779 """Check that bad compression methods passed to ZipFile.open are
1780 caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001781 self.assertRaises(NotImplementedError, zipfile.ZipFile, TESTFN, "w", -1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001782
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001783 def test_unsupported_compression(self):
1784 # data is declared as shrunk, but actually deflated
1785 data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001786 b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
1787 b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
1788 b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1789 b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
1790 b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001791 with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
1792 self.assertRaises(NotImplementedError, zipf.open, 'x')
1793
Ezio Melottiafd0d112009-07-15 17:17:17 +00001794 def test_null_byte_in_filename(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001795 """Check that a filename containing a null byte is properly
1796 terminated."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001797 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1798 zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
1799 self.assertEqual(zipf.namelist(), ['foo.txt'])
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001800
Ezio Melottiafd0d112009-07-15 17:17:17 +00001801 def test_struct_sizes(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001802 """Check that ZIP internal structure sizes are calculated correctly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001803 self.assertEqual(zipfile.sizeEndCentDir, 22)
1804 self.assertEqual(zipfile.sizeCentralDir, 46)
1805 self.assertEqual(zipfile.sizeEndCentDir64, 56)
1806 self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
1807
Ezio Melottiafd0d112009-07-15 17:17:17 +00001808 def test_comments(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001809 """Check that comments on the archive are handled properly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001810
1811 # check default comment is empty
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001812 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1813 self.assertEqual(zipf.comment, b'')
1814 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1815
1816 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1817 self.assertEqual(zipfr.comment, b'')
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001818
1819 # check a simple short comment
1820 comment = b'Bravely taking to his feet, he beat a very brave retreat.'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001821 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1822 zipf.comment = comment
1823 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1824 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1825 self.assertEqual(zipf.comment, comment)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001826
1827 # check a comment of max length
1828 comment2 = ''.join(['%d' % (i**3 % 10) for i in range((1 << 16)-1)])
1829 comment2 = comment2.encode("ascii")
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001830 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1831 zipf.comment = comment2
1832 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1833
1834 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1835 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001836
1837 # check a comment that is too long is truncated
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001838 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001839 with self.assertWarns(UserWarning):
1840 zipf.comment = comment2 + b'oops'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001841 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1842 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1843 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001844
Antoine Pitrouc3991852012-06-30 17:31:37 +02001845 # check that comments are correctly modified in append mode
1846 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1847 zipf.comment = b"original comment"
1848 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1849 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1850 zipf.comment = b"an updated comment"
1851 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1852 self.assertEqual(zipf.comment, b"an updated comment")
1853
1854 # check that comments are correctly shortened in append mode
1855 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1856 zipf.comment = b"original comment that's longer"
1857 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1858 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1859 zipf.comment = b"shorter comment"
1860 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1861 self.assertEqual(zipf.comment, b"shorter comment")
1862
R David Murrayf50b38a2012-04-12 18:44:58 -04001863 def test_unicode_comment(self):
1864 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1865 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1866 with self.assertRaises(TypeError):
1867 zipf.comment = "this is an error"
1868
1869 def test_change_comment_in_empty_archive(self):
1870 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1871 self.assertFalse(zipf.filelist)
1872 zipf.comment = b"this is a comment"
1873 with zipfile.ZipFile(TESTFN, "r") as zipf:
1874 self.assertEqual(zipf.comment, b"this is a comment")
1875
1876 def test_change_comment_in_nonempty_archive(self):
1877 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1878 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1879 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1880 self.assertTrue(zipf.filelist)
1881 zipf.comment = b"this is a comment"
1882 with zipfile.ZipFile(TESTFN, "r") as zipf:
1883 self.assertEqual(zipf.comment, b"this is a comment")
1884
Georg Brandl268e4d42010-10-14 06:59:45 +00001885 def test_empty_zipfile(self):
1886 # Check that creating a file in 'w' or 'a' mode and closing without
1887 # adding any files to the archives creates a valid empty ZIP file
1888 zipf = zipfile.ZipFile(TESTFN, mode="w")
1889 zipf.close()
1890 try:
1891 zipf = zipfile.ZipFile(TESTFN, mode="r")
1892 except zipfile.BadZipFile:
1893 self.fail("Unable to create empty ZIP file in 'w' mode")
1894
1895 zipf = zipfile.ZipFile(TESTFN, mode="a")
1896 zipf.close()
1897 try:
1898 zipf = zipfile.ZipFile(TESTFN, mode="r")
1899 except:
1900 self.fail("Unable to create empty ZIP file in 'a' mode")
1901
1902 def test_open_empty_file(self):
1903 # Issue 1710703: Check that opening a file with less than 22 bytes
Georg Brandl4d540882010-10-28 06:42:33 +00001904 # raises a BadZipFile exception (rather than the previously unhelpful
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001905 # OSError)
Georg Brandl268e4d42010-10-14 06:59:45 +00001906 f = open(TESTFN, 'w')
1907 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001908 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN, 'r')
Georg Brandl268e4d42010-10-14 06:59:45 +00001909
Senthil Kumaran29fa9d42011-10-20 01:46:00 +08001910 def test_create_zipinfo_before_1980(self):
1911 self.assertRaises(ValueError,
1912 zipfile.ZipInfo, 'seventies', (1979, 1, 1, 0, 0, 0))
1913
Mickaël Schoentgen992347d2019-09-09 15:08:54 +02001914 def test_create_empty_zipinfo_repr(self):
1915 """Before bpo-26185, repr() on empty ZipInfo object was failing."""
1916 zi = zipfile.ZipInfo(filename="empty")
1917 self.assertEqual(repr(zi), "<ZipInfo filename='empty' file_size=0>")
1918
1919 def test_create_empty_zipinfo_default_attributes(self):
1920 """Ensure all required attributes are set."""
1921 zi = zipfile.ZipInfo()
1922 self.assertEqual(zi.orig_filename, "NoName")
1923 self.assertEqual(zi.filename, "NoName")
1924 self.assertEqual(zi.date_time, (1980, 1, 1, 0, 0, 0))
1925 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
1926 self.assertEqual(zi.comment, b"")
1927 self.assertEqual(zi.extra, b"")
1928 self.assertIn(zi.create_system, (0, 3))
1929 self.assertEqual(zi.create_version, zipfile.DEFAULT_VERSION)
1930 self.assertEqual(zi.extract_version, zipfile.DEFAULT_VERSION)
1931 self.assertEqual(zi.reserved, 0)
1932 self.assertEqual(zi.flag_bits, 0)
1933 self.assertEqual(zi.volume, 0)
1934 self.assertEqual(zi.internal_attr, 0)
1935 self.assertEqual(zi.external_attr, 0)
1936
1937 # Before bpo-26185, both were missing
1938 self.assertEqual(zi.file_size, 0)
1939 self.assertEqual(zi.compress_size, 0)
1940
Gregory P. Smith0af8a862014-05-29 23:42:14 -07001941 def test_zipfile_with_short_extra_field(self):
1942 """If an extra field in the header is less than 4 bytes, skip it."""
1943 zipdata = (
1944 b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1945 b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1946 b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1947 b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1948 b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1949 b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1950 b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1951 )
1952 with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1953 # testzip returns the name of the first corrupt file, or None
1954 self.assertIsNone(zipf.testzip())
1955
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001956 def test_open_conflicting_handles(self):
1957 # It's only possible to open one writable file handle at a time
1958 msg1 = b"It's fun to charter an accountant!"
1959 msg2 = b"And sail the wide accountant sea"
1960 msg3 = b"To find, explore the funds offshore"
1961 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
1962 with zipf.open('foo', mode='w') as w2:
1963 w2.write(msg1)
1964 with zipf.open('bar', mode='w') as w1:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001965 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001966 zipf.open('handle', mode='w')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001967 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001968 zipf.open('foo', mode='r')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001969 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001970 zipf.writestr('str', 'abcde')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001971 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001972 zipf.write(__file__, 'file')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001973 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001974 zipf.close()
1975 w1.write(msg2)
1976 with zipf.open('baz', mode='w') as w2:
1977 w2.write(msg3)
1978
1979 with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1980 self.assertEqual(zipf.read('foo'), msg1)
1981 self.assertEqual(zipf.read('bar'), msg2)
1982 self.assertEqual(zipf.read('baz'), msg3)
1983 self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
1984
John Jolly066df4f2018-01-30 01:51:35 -07001985 def test_seek_tell(self):
1986 # Test seek functionality
1987 txt = b"Where's Bruce?"
1988 bloc = txt.find(b"Bruce")
1989 # Check seek on a file
1990 with zipfile.ZipFile(TESTFN, "w") as zipf:
1991 zipf.writestr("foo.txt", txt)
1992 with zipfile.ZipFile(TESTFN, "r") as zipf:
1993 with zipf.open("foo.txt", "r") as fp:
1994 fp.seek(bloc, os.SEEK_SET)
1995 self.assertEqual(fp.tell(), bloc)
1996 fp.seek(-bloc, os.SEEK_CUR)
1997 self.assertEqual(fp.tell(), 0)
1998 fp.seek(bloc, os.SEEK_CUR)
1999 self.assertEqual(fp.tell(), bloc)
2000 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
2001 fp.seek(0, os.SEEK_END)
2002 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02002003 fp.seek(0, os.SEEK_SET)
2004 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07002005 # Check seek on memory file
2006 data = io.BytesIO()
2007 with zipfile.ZipFile(data, mode="w") as zipf:
2008 zipf.writestr("foo.txt", txt)
2009 with zipfile.ZipFile(data, mode="r") as zipf:
2010 with zipf.open("foo.txt", "r") as fp:
2011 fp.seek(bloc, os.SEEK_SET)
2012 self.assertEqual(fp.tell(), bloc)
2013 fp.seek(-bloc, os.SEEK_CUR)
2014 self.assertEqual(fp.tell(), 0)
2015 fp.seek(bloc, os.SEEK_CUR)
2016 self.assertEqual(fp.tell(), bloc)
2017 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
2018 fp.seek(0, os.SEEK_END)
2019 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02002020 fp.seek(0, os.SEEK_SET)
2021 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07002022
Berker Peksag2f1b8572019-09-12 17:13:44 +03002023 @requires_bz2
2024 def test_decompress_without_3rd_party_library(self):
2025 data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
2026 zip_file = io.BytesIO(data)
2027 with zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_BZIP2) as zf:
2028 zf.writestr('a.txt', b'a')
2029 with mock.patch('zipfile.bz2', None):
2030 with zipfile.ZipFile(zip_file) as zf:
2031 self.assertRaises(RuntimeError, zf.extract, 'a.txt')
2032
Guido van Rossumd8faa362007-04-27 19:54:29 +00002033 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002034 unlink(TESTFN)
2035 unlink(TESTFN2)
2036
Thomas Wouterscf297e42007-02-23 15:07:44 +00002037
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002038class AbstractBadCrcTests:
2039 def test_testzip_with_bad_crc(self):
2040 """Tests that files with bad CRCs return their name from testzip."""
2041 zipdata = self.zip_with_bad_crc
2042
2043 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2044 # testzip returns the name of the first corrupt file, or None
2045 self.assertEqual('afile', zipf.testzip())
2046
2047 def test_read_with_bad_crc(self):
2048 """Tests that files with bad CRCs raise a BadZipFile exception when read."""
2049 zipdata = self.zip_with_bad_crc
2050
2051 # Using ZipFile.read()
2052 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2053 self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile')
2054
2055 # Using ZipExtFile.read()
2056 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2057 with zipf.open('afile', 'r') as corrupt_file:
2058 self.assertRaises(zipfile.BadZipFile, corrupt_file.read)
2059
2060 # Same with small reads (in order to exercise the buffering logic)
2061 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2062 with zipf.open('afile', 'r') as corrupt_file:
2063 corrupt_file.MIN_READ_SIZE = 2
2064 with self.assertRaises(zipfile.BadZipFile):
2065 while corrupt_file.read(2):
2066 pass
2067
2068
2069class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2070 compression = zipfile.ZIP_STORED
2071 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002072 b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
2073 b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
2074 b'ilehello,AworldP'
2075 b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
2076 b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
2077 b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
2078 b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
2079 b'\0\0/\0\0\0\0\0')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002080
2081@requires_zlib
2082class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2083 compression = zipfile.ZIP_DEFLATED
2084 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002085 b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
2086 b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2087 b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
2088 b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
2089 b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
2090 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
2091 b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
2092 b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002093
2094@requires_bz2
2095class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2096 compression = zipfile.ZIP_BZIP2
2097 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002098 b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA'
2099 b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2100 b'ileBZh91AY&SY\xd4\xa8\xca'
2101 b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5'
2102 b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f'
2103 b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14'
2104 b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8'
2105 b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'
2106 b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK'
2107 b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00'
2108 b'\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002109
2110@requires_lzma
2111class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2112 compression = zipfile.ZIP_LZMA
2113 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002114 b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2115 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2116 b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I'
2117 b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK'
2118 b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2119 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00'
2120 b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil'
2121 b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
2122 b'\x00>\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002123
2124
Thomas Wouterscf297e42007-02-23 15:07:44 +00002125class DecryptionTests(unittest.TestCase):
Ezio Melotti35386712009-12-31 13:22:41 +00002126 """Check that ZIP decryption works. Since the library does not
2127 support encryption at the moment, we use a pre-generated encrypted
2128 ZIP file."""
Thomas Wouterscf297e42007-02-23 15:07:44 +00002129
2130 data = (
Christian Tismer59202e52013-10-21 03:59:23 +02002131 b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
2132 b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
2133 b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
2134 b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
2135 b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
2136 b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
2137 b'\x00\x00L\x00\x00\x00\x00\x00' )
Christian Heimesfdab48e2008-01-20 09:06:41 +00002138 data2 = (
Christian Tismer59202e52013-10-21 03:59:23 +02002139 b'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
2140 b'\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
2141 b'\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
2142 b'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
2143 b'\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
2144 b'\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
2145 b'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
2146 b'\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
Thomas Wouterscf297e42007-02-23 15:07:44 +00002147
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002148 plain = b'zipfile.py encryption test'
Christian Heimesfdab48e2008-01-20 09:06:41 +00002149 plain2 = b'\x00'*512
Thomas Wouterscf297e42007-02-23 15:07:44 +00002150
2151 def setUp(self):
Ezio Melotti35386712009-12-31 13:22:41 +00002152 with open(TESTFN, "wb") as fp:
2153 fp.write(self.data)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002154 self.zip = zipfile.ZipFile(TESTFN, "r")
Ezio Melotti35386712009-12-31 13:22:41 +00002155 with open(TESTFN2, "wb") as fp:
2156 fp.write(self.data2)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002157 self.zip2 = zipfile.ZipFile(TESTFN2, "r")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002158
2159 def tearDown(self):
2160 self.zip.close()
2161 os.unlink(TESTFN)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002162 self.zip2.close()
2163 os.unlink(TESTFN2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002164
Ezio Melottiafd0d112009-07-15 17:17:17 +00002165 def test_no_password(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00002166 # Reading the encrypted file without password
2167 # must generate a RunTime exception
2168 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002169 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002170
Ezio Melottiafd0d112009-07-15 17:17:17 +00002171 def test_bad_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002172 self.zip.setpassword(b"perl")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002173 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002174 self.zip2.setpassword(b"perl")
2175 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Guido van Rossumd8faa362007-04-27 19:54:29 +00002176
Ezio Melotti975077a2011-05-19 22:03:22 +03002177 @requires_zlib
Ezio Melottiafd0d112009-07-15 17:17:17 +00002178 def test_good_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002179 self.zip.setpassword(b"python")
Ezio Melotti35386712009-12-31 13:22:41 +00002180 self.assertEqual(self.zip.read("test.txt"), self.plain)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002181 self.zip2.setpassword(b"12345")
Ezio Melotti35386712009-12-31 13:22:41 +00002182 self.assertEqual(self.zip2.read("zero"), self.plain2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002183
R. David Murray8d855d82010-12-21 21:53:37 +00002184 def test_unicode_password(self):
2185 self.assertRaises(TypeError, self.zip.setpassword, "unicode")
2186 self.assertRaises(TypeError, self.zip.read, "test.txt", "python")
2187 self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python")
2188 self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python")
2189
Serhiy Storchaka5c32af72019-10-27 10:22:14 +02002190 def test_seek_tell(self):
2191 self.zip.setpassword(b"python")
2192 txt = self.plain
2193 test_word = b'encryption'
2194 bloc = txt.find(test_word)
2195 bloc_len = len(test_word)
2196 with self.zip.open("test.txt", "r") as fp:
2197 fp.seek(bloc, os.SEEK_SET)
2198 self.assertEqual(fp.tell(), bloc)
2199 fp.seek(-bloc, os.SEEK_CUR)
2200 self.assertEqual(fp.tell(), 0)
2201 fp.seek(bloc, os.SEEK_CUR)
2202 self.assertEqual(fp.tell(), bloc)
2203 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2204
2205 # Make sure that the second read after seeking back beyond
2206 # _readbuffer returns the same content (ie. rewind to the start of
2207 # the file to read forward to the required position).
2208 old_read_size = fp.MIN_READ_SIZE
2209 fp.MIN_READ_SIZE = 1
2210 fp._readbuffer = b''
2211 fp._offset = 0
2212 fp.seek(0, os.SEEK_SET)
2213 self.assertEqual(fp.tell(), 0)
2214 fp.seek(bloc, os.SEEK_CUR)
2215 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2216 fp.MIN_READ_SIZE = old_read_size
2217
2218 fp.seek(0, os.SEEK_END)
2219 self.assertEqual(fp.tell(), len(txt))
2220 fp.seek(0, os.SEEK_SET)
2221 self.assertEqual(fp.tell(), 0)
2222
2223 # Read the file completely to definitely call any eof integrity
2224 # checks (crc) and make sure they still pass.
2225 fp.read()
2226
2227
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002228class AbstractTestsWithRandomBinaryFiles:
2229 @classmethod
2230 def setUpClass(cls):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002231 datacount = randint(16, 64)*1024 + randint(1, 1024)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002232 cls.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
2233 for i in range(datacount))
Guido van Rossumd8faa362007-04-27 19:54:29 +00002234
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002235 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002236 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +00002237 with open(TESTFN, "wb") as fp:
2238 fp.write(self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002239
2240 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002241 unlink(TESTFN)
2242 unlink(TESTFN2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002243
Ezio Melottiafd0d112009-07-15 17:17:17 +00002244 def make_test_archive(self, f, compression):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002245 # Create the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002246 with zipfile.ZipFile(f, "w", compression) as zipfp:
2247 zipfp.write(TESTFN, "another.name")
2248 zipfp.write(TESTFN, TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002249
Ezio Melottiafd0d112009-07-15 17:17:17 +00002250 def zip_test(self, f, compression):
2251 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002252
2253 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002254 with zipfile.ZipFile(f, "r", compression) as zipfp:
2255 testdata = zipfp.read(TESTFN)
2256 self.assertEqual(len(testdata), len(self.data))
2257 self.assertEqual(testdata, self.data)
2258 self.assertEqual(zipfp.read("another.name"), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002259
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002260 def test_read(self):
2261 for f in get_files(self):
2262 self.zip_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002263
Ezio Melottiafd0d112009-07-15 17:17:17 +00002264 def zip_open_test(self, f, compression):
2265 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002266
2267 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002268 with zipfile.ZipFile(f, "r", compression) as zipfp:
2269 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002270 with zipfp.open(TESTFN) as zipopen1:
2271 while True:
2272 read_data = zipopen1.read(256)
2273 if not read_data:
2274 break
2275 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002276
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002277 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002278 with zipfp.open("another.name") as zipopen2:
2279 while True:
2280 read_data = zipopen2.read(256)
2281 if not read_data:
2282 break
2283 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002284
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002285 testdata1 = b''.join(zipdata1)
2286 self.assertEqual(len(testdata1), len(self.data))
2287 self.assertEqual(testdata1, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002288
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002289 testdata2 = b''.join(zipdata2)
Ezio Melotti35386712009-12-31 13:22:41 +00002290 self.assertEqual(len(testdata2), len(self.data))
2291 self.assertEqual(testdata2, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002292
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002293 def test_open(self):
2294 for f in get_files(self):
2295 self.zip_open_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002296
Ezio Melottiafd0d112009-07-15 17:17:17 +00002297 def zip_random_open_test(self, f, compression):
2298 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002299
2300 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002301 with zipfile.ZipFile(f, "r", compression) as zipfp:
2302 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002303 with zipfp.open(TESTFN) as zipopen1:
2304 while True:
2305 read_data = zipopen1.read(randint(1, 1024))
2306 if not read_data:
2307 break
2308 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002309
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002310 testdata = b''.join(zipdata1)
2311 self.assertEqual(len(testdata), len(self.data))
2312 self.assertEqual(testdata, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002313
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002314 def test_random_open(self):
2315 for f in get_files(self):
2316 self.zip_random_open_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002317
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00002318
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002319class StoredTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2320 unittest.TestCase):
2321 compression = zipfile.ZIP_STORED
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02002322
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002323@requires_zlib
2324class DeflateTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2325 unittest.TestCase):
2326 compression = zipfile.ZIP_DEFLATED
2327
2328@requires_bz2
2329class Bzip2TestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2330 unittest.TestCase):
2331 compression = zipfile.ZIP_BZIP2
2332
2333@requires_lzma
2334class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2335 unittest.TestCase):
2336 compression = zipfile.ZIP_LZMA
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002337
Ezio Melotti76430242009-07-11 18:28:48 +00002338
luzpaza5293b42017-11-05 07:37:50 -06002339# Provide the tell() method but not seek()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002340class Tellable:
2341 def __init__(self, fp):
2342 self.fp = fp
2343 self.offset = 0
2344
2345 def write(self, data):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002346 n = self.fp.write(data)
2347 self.offset += n
2348 return n
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002349
2350 def tell(self):
2351 return self.offset
2352
2353 def flush(self):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002354 self.fp.flush()
2355
2356class Unseekable:
2357 def __init__(self, fp):
2358 self.fp = fp
2359
2360 def write(self, data):
2361 return self.fp.write(data)
2362
2363 def flush(self):
2364 self.fp.flush()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002365
2366class UnseekableTests(unittest.TestCase):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002367 def test_writestr(self):
2368 for wrapper in (lambda f: f), Tellable, Unseekable:
2369 with self.subTest(wrapper=wrapper):
2370 f = io.BytesIO()
2371 f.write(b'abc')
2372 bf = io.BufferedWriter(f)
2373 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2374 zipfp.writestr('ones', b'111')
2375 zipfp.writestr('twos', b'222')
2376 self.assertEqual(f.getvalue()[:5], b'abcPK')
2377 with zipfile.ZipFile(f, mode='r') as zipf:
2378 with zipf.open('ones') as zopen:
2379 self.assertEqual(zopen.read(), b'111')
2380 with zipf.open('twos') as zopen:
2381 self.assertEqual(zopen.read(), b'222')
2382
2383 def test_write(self):
2384 for wrapper in (lambda f: f), Tellable, Unseekable:
2385 with self.subTest(wrapper=wrapper):
2386 f = io.BytesIO()
2387 f.write(b'abc')
2388 bf = io.BufferedWriter(f)
2389 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2390 self.addCleanup(unlink, TESTFN)
2391 with open(TESTFN, 'wb') as f2:
2392 f2.write(b'111')
2393 zipfp.write(TESTFN, 'ones')
2394 with open(TESTFN, 'wb') as f2:
2395 f2.write(b'222')
2396 zipfp.write(TESTFN, 'twos')
2397 self.assertEqual(f.getvalue()[:5], b'abcPK')
2398 with zipfile.ZipFile(f, mode='r') as zipf:
2399 with zipf.open('ones') as zopen:
2400 self.assertEqual(zopen.read(), b'111')
2401 with zipf.open('twos') as zopen:
2402 self.assertEqual(zopen.read(), b'222')
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002403
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002404 def test_open_write(self):
2405 for wrapper in (lambda f: f), Tellable, Unseekable:
2406 with self.subTest(wrapper=wrapper):
2407 f = io.BytesIO()
2408 f.write(b'abc')
2409 bf = io.BufferedWriter(f)
2410 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
2411 with zipf.open('ones', 'w') as zopen:
2412 zopen.write(b'111')
2413 with zipf.open('twos', 'w') as zopen:
2414 zopen.write(b'222')
2415 self.assertEqual(f.getvalue()[:5], b'abcPK')
2416 with zipfile.ZipFile(f) as zipf:
2417 self.assertEqual(zipf.read('ones'), b'111')
2418 self.assertEqual(zipf.read('twos'), b'222')
2419
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002420
Ezio Melotti975077a2011-05-19 22:03:22 +03002421@requires_zlib
Guido van Rossumd8faa362007-04-27 19:54:29 +00002422class TestsWithMultipleOpens(unittest.TestCase):
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002423 @classmethod
2424 def setUpClass(cls):
2425 cls.data1 = b'111' + getrandbytes(10000)
2426 cls.data2 = b'222' + getrandbytes(10000)
2427
2428 def make_test_archive(self, f):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002429 # Create the ZIP archive
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002430 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
2431 zipfp.writestr('ones', self.data1)
2432 zipfp.writestr('twos', self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002433
Ezio Melottiafd0d112009-07-15 17:17:17 +00002434 def test_same_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002435 # Verify that (when the ZipFile is in control of creating file objects)
2436 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002437 for f in get_files(self):
2438 self.make_test_archive(f)
2439 with zipfile.ZipFile(f, mode="r") as zipf:
2440 with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
2441 data1 = zopen1.read(500)
2442 data2 = zopen2.read(500)
2443 data1 += zopen1.read()
2444 data2 += zopen2.read()
2445 self.assertEqual(data1, data2)
2446 self.assertEqual(data1, self.data1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002447
Ezio Melottiafd0d112009-07-15 17:17:17 +00002448 def test_different_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002449 # Verify that (when the ZipFile is in control of creating file objects)
2450 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002451 for f in get_files(self):
2452 self.make_test_archive(f)
2453 with zipfile.ZipFile(f, mode="r") as zipf:
2454 with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
2455 data1 = zopen1.read(500)
2456 data2 = zopen2.read(500)
2457 data1 += zopen1.read()
2458 data2 += zopen2.read()
2459 self.assertEqual(data1, self.data1)
2460 self.assertEqual(data2, self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002461
Ezio Melottiafd0d112009-07-15 17:17:17 +00002462 def test_interleaved(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002463 # Verify that (when the ZipFile is in control of creating file objects)
2464 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002465 for f in get_files(self):
2466 self.make_test_archive(f)
2467 with zipfile.ZipFile(f, mode="r") as zipf:
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002468 with zipf.open('ones') as zopen1:
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002469 data1 = zopen1.read(500)
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002470 with zipf.open('twos') as zopen2:
2471 data2 = zopen2.read(500)
2472 data1 += zopen1.read()
2473 data2 += zopen2.read()
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002474 self.assertEqual(data1, self.data1)
2475 self.assertEqual(data2, self.data2)
2476
2477 def test_read_after_close(self):
2478 for f in get_files(self):
2479 self.make_test_archive(f)
2480 with contextlib.ExitStack() as stack:
2481 with zipfile.ZipFile(f, 'r') as zipf:
2482 zopen1 = stack.enter_context(zipf.open('ones'))
2483 zopen2 = stack.enter_context(zipf.open('twos'))
Brian Curtin8fb9b862010-11-18 02:15:28 +00002484 data1 = zopen1.read(500)
2485 data2 = zopen2.read(500)
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002486 data1 += zopen1.read()
2487 data2 += zopen2.read()
2488 self.assertEqual(data1, self.data1)
2489 self.assertEqual(data2, self.data2)
2490
2491 def test_read_after_write(self):
2492 for f in get_files(self):
2493 with zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as zipf:
2494 zipf.writestr('ones', self.data1)
2495 zipf.writestr('twos', self.data2)
2496 with zipf.open('ones') as zopen1:
2497 data1 = zopen1.read(500)
2498 self.assertEqual(data1, self.data1[:500])
2499 with zipfile.ZipFile(f, 'r') as zipf:
2500 data1 = zipf.read('ones')
2501 data2 = zipf.read('twos')
2502 self.assertEqual(data1, self.data1)
2503 self.assertEqual(data2, self.data2)
2504
2505 def test_write_after_read(self):
2506 for f in get_files(self):
2507 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipf:
2508 zipf.writestr('ones', self.data1)
2509 with zipf.open('ones') as zopen1:
2510 zopen1.read(500)
2511 zipf.writestr('twos', self.data2)
2512 with zipfile.ZipFile(f, 'r') as zipf:
2513 data1 = zipf.read('ones')
2514 data2 = zipf.read('twos')
2515 self.assertEqual(data1, self.data1)
2516 self.assertEqual(data2, self.data2)
2517
2518 def test_many_opens(self):
2519 # Verify that read() and open() promptly close the file descriptor,
2520 # and don't rely on the garbage collector to free resources.
2521 self.make_test_archive(TESTFN2)
2522 with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
2523 for x in range(100):
2524 zipf.read('ones')
2525 with zipf.open('ones') as zopen1:
2526 pass
2527 with open(os.devnull) as f:
2528 self.assertLess(f.fileno(), 100)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002529
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002530 def test_write_while_reading(self):
2531 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
2532 zipf.writestr('ones', self.data1)
2533 with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
2534 with zipf.open('ones', 'r') as r1:
2535 data1 = r1.read(500)
2536 with zipf.open('twos', 'w') as w1:
2537 w1.write(self.data2)
2538 data1 += r1.read()
2539 self.assertEqual(data1, self.data1)
2540 with zipfile.ZipFile(TESTFN2) as zipf:
2541 self.assertEqual(zipf.read('twos'), self.data2)
2542
Guido van Rossumd8faa362007-04-27 19:54:29 +00002543 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002544 unlink(TESTFN2)
2545
Guido van Rossumd8faa362007-04-27 19:54:29 +00002546
Martin v. Löwis59e47792009-01-24 14:10:07 +00002547class TestWithDirectory(unittest.TestCase):
2548 def setUp(self):
2549 os.mkdir(TESTFN2)
2550
Ezio Melottiafd0d112009-07-15 17:17:17 +00002551 def test_extract_dir(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002552 with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
2553 zipf.extractall(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002554 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
2555 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
2556 self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
2557
Ezio Melottiafd0d112009-07-15 17:17:17 +00002558 def test_bug_6050(self):
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002559 # Extraction should succeed if directories already exist
2560 os.mkdir(os.path.join(TESTFN2, "a"))
Ezio Melottiafd0d112009-07-15 17:17:17 +00002561 self.test_extract_dir()
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002562
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002563 def test_write_dir(self):
2564 dirpath = os.path.join(TESTFN2, "x")
2565 os.mkdir(dirpath)
2566 mode = os.stat(dirpath).st_mode & 0xFFFF
2567 with zipfile.ZipFile(TESTFN, "w") as zipf:
2568 zipf.write(dirpath)
2569 zinfo = zipf.filelist[0]
2570 self.assertTrue(zinfo.filename.endswith("/x/"))
2571 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2572 zipf.write(dirpath, "y")
2573 zinfo = zipf.filelist[1]
2574 self.assertTrue(zinfo.filename, "y/")
2575 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2576 with zipfile.ZipFile(TESTFN, "r") as zipf:
2577 zinfo = zipf.filelist[0]
2578 self.assertTrue(zinfo.filename.endswith("/x/"))
2579 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2580 zinfo = zipf.filelist[1]
2581 self.assertTrue(zinfo.filename, "y/")
2582 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2583 target = os.path.join(TESTFN2, "target")
2584 os.mkdir(target)
2585 zipf.extractall(target)
2586 self.assertTrue(os.path.isdir(os.path.join(target, "y")))
2587 self.assertEqual(len(os.listdir(target)), 2)
2588
2589 def test_writestr_dir(self):
Martin v. Löwis59e47792009-01-24 14:10:07 +00002590 os.mkdir(os.path.join(TESTFN2, "x"))
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002591 with zipfile.ZipFile(TESTFN, "w") as zipf:
2592 zipf.writestr("x/", b'')
2593 zinfo = zipf.filelist[0]
2594 self.assertEqual(zinfo.filename, "x/")
2595 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2596 with zipfile.ZipFile(TESTFN, "r") as zipf:
2597 zinfo = zipf.filelist[0]
2598 self.assertTrue(zinfo.filename.endswith("x/"))
2599 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2600 target = os.path.join(TESTFN2, "target")
2601 os.mkdir(target)
2602 zipf.extractall(target)
2603 self.assertTrue(os.path.isdir(os.path.join(target, "x")))
2604 self.assertEqual(os.listdir(target), ["x"])
Martin v. Löwis59e47792009-01-24 14:10:07 +00002605
2606 def tearDown(self):
Victor Stinner57004c62014-09-04 00:49:01 +02002607 rmtree(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002608 if os.path.exists(TESTFN):
Ezio Melotti76430242009-07-11 18:28:48 +00002609 unlink(TESTFN)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002610
Guido van Rossumd8faa362007-04-27 19:54:29 +00002611
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002612class ZipInfoTests(unittest.TestCase):
2613 def test_from_file(self):
2614 zi = zipfile.ZipInfo.from_file(__file__)
2615 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2616 self.assertFalse(zi.is_dir())
Serhiy Storchaka8606e952017-03-08 14:37:51 +02002617 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2618
2619 def test_from_file_pathlike(self):
2620 zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
2621 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2622 self.assertFalse(zi.is_dir())
2623 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2624
2625 def test_from_file_bytes(self):
2626 zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
2627 self.assertEqual(posixpath.basename(zi.filename), 'test')
2628 self.assertFalse(zi.is_dir())
2629 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2630
2631 def test_from_file_fileno(self):
2632 with open(__file__, 'rb') as f:
2633 zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
2634 self.assertEqual(posixpath.basename(zi.filename), 'test')
2635 self.assertFalse(zi.is_dir())
2636 self.assertEqual(zi.file_size, os.path.getsize(__file__))
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002637
2638 def test_from_dir(self):
2639 dirpath = os.path.dirname(os.path.abspath(__file__))
2640 zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
2641 self.assertEqual(zi.filename, 'stdlib_tests/')
2642 self.assertTrue(zi.is_dir())
2643 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
2644 self.assertEqual(zi.file_size, 0)
2645
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002646
2647class CommandLineTest(unittest.TestCase):
2648
2649 def zipfilecmd(self, *args, **kwargs):
2650 rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args,
2651 **kwargs)
2652 return out.replace(os.linesep.encode(), b'\n')
2653
2654 def zipfilecmd_failure(self, *args):
2655 return script_helper.assert_python_failure('-m', 'zipfile', *args)
2656
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002657 def test_bad_use(self):
2658 rc, out, err = self.zipfilecmd_failure()
2659 self.assertEqual(out, b'')
2660 self.assertIn(b'usage', err.lower())
2661 self.assertIn(b'error', err.lower())
2662 self.assertIn(b'required', err.lower())
2663 rc, out, err = self.zipfilecmd_failure('-l', '')
2664 self.assertEqual(out, b'')
2665 self.assertNotEqual(err.strip(), b'')
2666
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002667 def test_test_command(self):
2668 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002669 for opt in '-t', '--test':
2670 out = self.zipfilecmd(opt, zip_name)
2671 self.assertEqual(out.rstrip(), b'Done testing')
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002672 zip_name = findfile('testtar.tar')
2673 rc, out, err = self.zipfilecmd_failure('-t', zip_name)
2674 self.assertEqual(out, b'')
2675
2676 def test_list_command(self):
2677 zip_name = findfile('zipdir.zip')
2678 t = io.StringIO()
2679 with zipfile.ZipFile(zip_name, 'r') as tf:
2680 tf.printdir(t)
2681 expected = t.getvalue().encode('ascii', 'backslashreplace')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002682 for opt in '-l', '--list':
2683 out = self.zipfilecmd(opt, zip_name,
2684 PYTHONIOENCODING='ascii:backslashreplace')
2685 self.assertEqual(out, expected)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002686
Serhiy Storchakab4293ef2016-10-23 22:32:30 +03002687 @requires_zlib
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002688 def test_create_command(self):
2689 self.addCleanup(unlink, TESTFN)
2690 with open(TESTFN, 'w') as f:
2691 f.write('test 1')
2692 os.mkdir(TESTFNDIR)
2693 self.addCleanup(rmtree, TESTFNDIR)
2694 with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f:
2695 f.write('test 2')
2696 files = [TESTFN, TESTFNDIR]
2697 namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt']
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002698 for opt in '-c', '--create':
2699 try:
2700 out = self.zipfilecmd(opt, TESTFN2, *files)
2701 self.assertEqual(out, b'')
2702 with zipfile.ZipFile(TESTFN2) as zf:
2703 self.assertEqual(zf.namelist(), namelist)
2704 self.assertEqual(zf.read(namelist[0]), b'test 1')
2705 self.assertEqual(zf.read(namelist[2]), b'test 2')
2706 finally:
2707 unlink(TESTFN2)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002708
2709 def test_extract_command(self):
2710 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002711 for opt in '-e', '--extract':
2712 with temp_dir() as extdir:
2713 out = self.zipfilecmd(opt, zip_name, extdir)
2714 self.assertEqual(out, b'')
2715 with zipfile.ZipFile(zip_name) as zf:
2716 for zi in zf.infolist():
2717 path = os.path.join(extdir,
2718 zi.filename.replace('/', os.sep))
2719 if zi.is_dir():
2720 self.assertTrue(os.path.isdir(path))
2721 else:
2722 self.assertTrue(os.path.isfile(path))
2723 with open(path, 'rb') as f:
2724 self.assertEqual(f.read(), zf.read(zi))
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002725
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002726
2727# Poor man's technique to consume a (smallish) iterable.
2728consume = tuple
2729
2730
shireenraoa4e29912019-08-24 11:26:41 -04002731def add_dirs(zf):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002732 """
shireenraoa4e29912019-08-24 11:26:41 -04002733 Given a writable zip file zf, inject directory entries for
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002734 any directories implied by the presence of children.
2735 """
shireenraoa4e29912019-08-24 11:26:41 -04002736 for name in zipfile.Path._implied_dirs(zf.namelist()):
2737 zf.writestr(name, b"")
2738 return zf
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002739
2740
shireenraoa4e29912019-08-24 11:26:41 -04002741def build_alpharep_fixture():
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002742 """
2743 Create a zip file with this structure:
2744
2745 .
2746 ├── a.txt
shireenraoa4e29912019-08-24 11:26:41 -04002747 ├── b
2748 │ ├── c.txt
2749 │ ├── d
2750 │ │ └── e.txt
2751 │ └── f.txt
2752 └── g
2753 └── h
2754 └── i.txt
2755
2756 This fixture has the following key characteristics:
2757
2758 - a file at the root (a)
2759 - a file two levels deep (b/d/e)
2760 - multiple files in a directory (b/c, b/f)
2761 - a directory containing only a directory (g/h)
2762
2763 "alpha" because it uses alphabet
2764 "rep" because it's a representative example
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002765 """
2766 data = io.BytesIO()
2767 zf = zipfile.ZipFile(data, "w")
2768 zf.writestr("a.txt", b"content of a")
2769 zf.writestr("b/c.txt", b"content of c")
2770 zf.writestr("b/d/e.txt", b"content of e")
shireenraoa4e29912019-08-24 11:26:41 -04002771 zf.writestr("b/f.txt", b"content of f")
2772 zf.writestr("g/h/i.txt", b"content of i")
2773 zf.filename = "alpharep.zip"
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002774 return zf
2775
2776
Gregory P. Smith3f4db4a2019-09-10 17:14:11 +01002777class TestExecutablePrependedZip(unittest.TestCase):
2778 """Test our ability to open zip files with an executable prepended."""
2779
2780 def setUp(self):
2781 self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
2782 self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
2783
2784 def _test_zip_works(self, name):
2785 # bpo-28494 sanity check: ensure is_zipfile works on these.
2786 self.assertTrue(zipfile.is_zipfile(name),
2787 f'is_zipfile failed on {name}')
2788 # Ensure we can operate on these via ZipFile.
2789 with zipfile.ZipFile(name) as zipfp:
2790 for n in zipfp.namelist():
2791 data = zipfp.read(n)
2792 self.assertIn(b'FAVORITE_NUMBER', data)
2793
2794 def test_read_zip_with_exe_prepended(self):
2795 self._test_zip_works(self.exe_zip)
2796
2797 def test_read_zip64_with_exe_prepended(self):
2798 self._test_zip_works(self.exe_zip64)
2799
2800 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2801 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2802 'Test relies on #!/bin/bash working.')
2803 def test_execute_zip2(self):
2804 output = subprocess.check_output([self.exe_zip, sys.executable])
2805 self.assertIn(b'number in executable: 5', output)
2806
2807 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2808 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2809 'Test relies on #!/bin/bash working.')
2810 def test_execute_zip64(self):
2811 output = subprocess.check_output([self.exe_zip64, sys.executable])
2812 self.assertIn(b'number in executable: 5', output)
2813
2814
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002815class TestPath(unittest.TestCase):
2816 def setUp(self):
2817 self.fixtures = contextlib.ExitStack()
2818 self.addCleanup(self.fixtures.close)
2819
shireenraoa4e29912019-08-24 11:26:41 -04002820 def zipfile_alpharep(self):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002821 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002822 yield build_alpharep_fixture()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002823 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002824 yield add_dirs(build_alpharep_fixture())
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002825
2826 def zipfile_ondisk(self):
2827 tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
shireenraoa4e29912019-08-24 11:26:41 -04002828 for alpharep in self.zipfile_alpharep():
2829 buffer = alpharep.fp
2830 alpharep.close()
2831 path = tmpdir / alpharep.filename
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002832 with path.open("wb") as strm:
2833 strm.write(buffer.getvalue())
2834 yield path
2835
shireenraoa4e29912019-08-24 11:26:41 -04002836 def test_iterdir_and_types(self):
2837 for alpharep in self.zipfile_alpharep():
2838 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002839 assert root.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002840 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002841 assert a.is_file()
2842 assert b.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002843 assert g.is_dir()
2844 c, f, d = b.iterdir()
2845 assert c.is_file() and f.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002846 e, = d.iterdir()
2847 assert e.is_file()
shireenraoa4e29912019-08-24 11:26:41 -04002848 h, = g.iterdir()
2849 i, = h.iterdir()
2850 assert i.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002851
2852 def test_open(self):
shireenraoa4e29912019-08-24 11:26:41 -04002853 for alpharep in self.zipfile_alpharep():
2854 root = zipfile.Path(alpharep)
2855 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002856 with a.open() as strm:
2857 data = strm.read()
2858 assert data == b"content of a"
2859
2860 def test_read(self):
shireenraoa4e29912019-08-24 11:26:41 -04002861 for alpharep in self.zipfile_alpharep():
2862 root = zipfile.Path(alpharep)
2863 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002864 assert a.read_text() == "content of a"
2865 assert a.read_bytes() == b"content of a"
2866
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002867 def test_joinpath(self):
shireenraoa4e29912019-08-24 11:26:41 -04002868 for alpharep in self.zipfile_alpharep():
2869 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002870 a = root.joinpath("a")
2871 assert a.is_file()
2872 e = root.joinpath("b").joinpath("d").joinpath("e.txt")
2873 assert e.read_text() == "content of e"
2874
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002875 def test_traverse_truediv(self):
shireenraoa4e29912019-08-24 11:26:41 -04002876 for alpharep in self.zipfile_alpharep():
2877 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002878 a = root / "a"
2879 assert a.is_file()
2880 e = root / "b" / "d" / "e.txt"
2881 assert e.read_text() == "content of e"
2882
2883 def test_pathlike_construction(self):
2884 """
2885 zipfile.Path should be constructable from a path-like object
2886 """
2887 for zipfile_ondisk in self.zipfile_ondisk():
2888 pathlike = pathlib.Path(str(zipfile_ondisk))
2889 zipfile.Path(pathlike)
2890
2891 def test_traverse_pathlike(self):
shireenraoa4e29912019-08-24 11:26:41 -04002892 for alpharep in self.zipfile_alpharep():
2893 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002894 root / pathlib.Path("a")
2895
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002896 def test_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002897 for alpharep in self.zipfile_alpharep():
2898 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002899 assert (root / 'a').parent.at == ''
2900 assert (root / 'a' / 'b').parent.at == 'a/'
2901
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002902 def test_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002903 for alpharep in self.zipfile_alpharep():
2904 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002905 assert (root / 'b').parent.at == ''
2906 assert (root / 'b/').parent.at == ''
2907
2908 def test_missing_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002909 for alpharep in self.zipfile_alpharep():
2910 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002911 assert (root / 'missing dir/').parent.at == ''
2912
shireenraoa4e29912019-08-24 11:26:41 -04002913
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00002914if __name__ == "__main__":
Brett Cannond5b4e1d2013-06-12 19:57:19 -04002915 unittest.main()