blob: 66f05ac1f3aef064105c11e2e5ec40a2ef840d52 [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
Marcel Plch7b41dba2018-08-03 17:59:19 +0200614 try:
615 os.utime(TESTFN, (4386268800, 4386268800))
616 except OverflowError:
617 self.skipTest('Host fs cannot set timestamp to required value.')
618
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200619 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
620 self.assertRaises(struct.error, zipfp.write, TESTFN)
621
Marcel Plch77b112c2018-08-31 16:43:31 +0200622 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
623 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200624 zinfo = zipfp.getinfo(TESTFN)
625 self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
626
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200627
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300628@requires_zlib
629class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,
630 unittest.TestCase):
631 compression = zipfile.ZIP_DEFLATED
632
Ezio Melottiafd0d112009-07-15 17:17:17 +0000633 def test_per_file_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000634 """Check that files within a Zip archive can have different
635 compression options."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000636 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
637 zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
638 zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
639 sinfo = zipfp.getinfo('storeme')
640 dinfo = zipfp.getinfo('deflateme')
641 self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
642 self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000643
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300644@requires_bz2
645class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile,
646 unittest.TestCase):
647 compression = zipfile.ZIP_BZIP2
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000648
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300649@requires_lzma
650class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile,
651 unittest.TestCase):
652 compression = zipfile.ZIP_LZMA
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000653
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300654
655class AbstractTestZip64InSmallFiles:
656 # These tests test the ZIP64 functionality without using large files,
657 # see test_zipfile64 for proper tests.
658
659 @classmethod
660 def setUpClass(cls):
661 line_gen = (bytes("Test of zipfile line %d." % i, "ascii")
662 for i in range(0, FIXEDTEST_SIZE))
663 cls.data = b'\n'.join(line_gen)
664
665 def setUp(self):
666 self._limit = zipfile.ZIP64_LIMIT
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300667 self._filecount_limit = zipfile.ZIP_FILECOUNT_LIMIT
668 zipfile.ZIP64_LIMIT = 1000
669 zipfile.ZIP_FILECOUNT_LIMIT = 9
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300670
671 # Make a source file with some lines
672 with open(TESTFN, "wb") as fp:
673 fp.write(self.data)
674
675 def zip_test(self, f, compression):
676 # Create the ZIP archive
677 with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
678 zipfp.write(TESTFN, "another.name")
679 zipfp.write(TESTFN, TESTFN)
680 zipfp.writestr("strfile", self.data)
681
682 # Read the ZIP archive
683 with zipfile.ZipFile(f, "r", compression) as zipfp:
684 self.assertEqual(zipfp.read(TESTFN), self.data)
685 self.assertEqual(zipfp.read("another.name"), self.data)
686 self.assertEqual(zipfp.read("strfile"), self.data)
687
688 # Print the ZIP directory
689 fp = io.StringIO()
690 zipfp.printdir(fp)
691
692 directory = fp.getvalue()
693 lines = directory.splitlines()
694 self.assertEqual(len(lines), 4) # Number of files + header
695
696 self.assertIn('File Name', lines[0])
697 self.assertIn('Modified', lines[0])
698 self.assertIn('Size', lines[0])
699
700 fn, date, time_, size = lines[1].split()
701 self.assertEqual(fn, 'another.name')
702 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
703 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
704 self.assertEqual(size, str(len(self.data)))
705
706 # Check the namelist
707 names = zipfp.namelist()
708 self.assertEqual(len(names), 3)
709 self.assertIn(TESTFN, names)
710 self.assertIn("another.name", names)
711 self.assertIn("strfile", names)
712
713 # Check infolist
714 infos = zipfp.infolist()
715 names = [i.filename for i in infos]
716 self.assertEqual(len(names), 3)
717 self.assertIn(TESTFN, names)
718 self.assertIn("another.name", names)
719 self.assertIn("strfile", names)
720 for i in infos:
721 self.assertEqual(i.file_size, len(self.data))
722
723 # check getinfo
724 for nm in (TESTFN, "another.name", "strfile"):
725 info = zipfp.getinfo(nm)
726 self.assertEqual(info.filename, nm)
727 self.assertEqual(info.file_size, len(self.data))
728
729 # Check that testzip doesn't raise an exception
730 zipfp.testzip()
731
732 def test_basic(self):
733 for f in get_files(self):
734 self.zip_test(f, self.compression)
735
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300736 def test_too_many_files(self):
737 # This test checks that more than 64k files can be added to an archive,
738 # and that the resulting archive can be read properly by ZipFile
739 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
740 allowZip64=True)
741 zipf.debug = 100
742 numfiles = 15
743 for i in range(numfiles):
744 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
745 self.assertEqual(len(zipf.namelist()), numfiles)
746 zipf.close()
747
748 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
749 self.assertEqual(len(zipf2.namelist()), numfiles)
750 for i in range(numfiles):
751 content = zipf2.read("foo%08d" % i).decode('ascii')
752 self.assertEqual(content, "%d" % (i**3 % 57))
753 zipf2.close()
754
755 def test_too_many_files_append(self):
756 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
757 allowZip64=False)
758 zipf.debug = 100
759 numfiles = 9
760 for i in range(numfiles):
761 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
762 self.assertEqual(len(zipf.namelist()), numfiles)
763 with self.assertRaises(zipfile.LargeZipFile):
764 zipf.writestr("foo%08d" % numfiles, b'')
765 self.assertEqual(len(zipf.namelist()), numfiles)
766 zipf.close()
767
768 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
769 allowZip64=False)
770 zipf.debug = 100
771 self.assertEqual(len(zipf.namelist()), numfiles)
772 with self.assertRaises(zipfile.LargeZipFile):
773 zipf.writestr("foo%08d" % numfiles, b'')
774 self.assertEqual(len(zipf.namelist()), numfiles)
775 zipf.close()
776
777 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
778 allowZip64=True)
779 zipf.debug = 100
780 self.assertEqual(len(zipf.namelist()), numfiles)
781 numfiles2 = 15
782 for i in range(numfiles, numfiles2):
783 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
784 self.assertEqual(len(zipf.namelist()), numfiles2)
785 zipf.close()
786
787 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
788 self.assertEqual(len(zipf2.namelist()), numfiles2)
789 for i in range(numfiles2):
790 content = zipf2.read("foo%08d" % i).decode('ascii')
791 self.assertEqual(content, "%d" % (i**3 % 57))
792 zipf2.close()
793
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300794 def tearDown(self):
795 zipfile.ZIP64_LIMIT = self._limit
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300796 zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300797 unlink(TESTFN)
798 unlink(TESTFN2)
799
800
801class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
802 unittest.TestCase):
803 compression = zipfile.ZIP_STORED
804
805 def large_file_exception_test(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200806 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300807 self.assertRaises(zipfile.LargeZipFile,
808 zipfp.write, TESTFN, "another.name")
809
810 def large_file_exception_test2(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200811 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300812 self.assertRaises(zipfile.LargeZipFile,
813 zipfp.writestr, "another.name", self.data)
814
815 def test_large_file_exception(self):
816 for f in get_files(self):
817 self.large_file_exception_test(f, zipfile.ZIP_STORED)
818 self.large_file_exception_test2(f, zipfile.ZIP_STORED)
819
820 def test_absolute_arcnames(self):
821 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
822 allowZip64=True) as zipfp:
823 zipfp.write(TESTFN, "/absolute")
824
825 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
826 self.assertEqual(zipfp.namelist(), ["absolute"])
827
Serhiy Storchaka9bdb7be2018-09-17 15:36:40 +0300828 def test_append(self):
829 # Test that appending to the Zip64 archive doesn't change
830 # extra fields of existing entries.
831 with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp:
832 zipfp.writestr("strfile", self.data)
833 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
834 zinfo = zipfp.getinfo("strfile")
835 extra = zinfo.extra
836 with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp:
837 zipfp.writestr("strfile2", self.data)
838 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
839 zinfo = zipfp.getinfo("strfile")
840 self.assertEqual(zinfo.extra, extra)
841
Daniel Hillierda6ce582019-10-29 18:24:18 +1100842 def make_zip64_file(
843 self, file_size_64_set=False, file_size_extra=False,
844 compress_size_64_set=False, compress_size_extra=False,
845 header_offset_64_set=False, header_offset_extra=False,
846 ):
847 """Generate bytes sequence for a zip with (incomplete) zip64 data.
848
849 The actual values (not the zip 64 0xffffffff values) stored in the file
850 are:
851 file_size: 8
852 compress_size: 8
853 header_offset: 0
854 """
855 actual_size = 8
856 actual_header_offset = 0
857 local_zip64_fields = []
858 central_zip64_fields = []
859
860 file_size = actual_size
861 if file_size_64_set:
862 file_size = 0xffffffff
863 if file_size_extra:
864 local_zip64_fields.append(actual_size)
865 central_zip64_fields.append(actual_size)
866 file_size = struct.pack("<L", file_size)
867
868 compress_size = actual_size
869 if compress_size_64_set:
870 compress_size = 0xffffffff
871 if compress_size_extra:
872 local_zip64_fields.append(actual_size)
873 central_zip64_fields.append(actual_size)
874 compress_size = struct.pack("<L", compress_size)
875
876 header_offset = actual_header_offset
877 if header_offset_64_set:
878 header_offset = 0xffffffff
879 if header_offset_extra:
880 central_zip64_fields.append(actual_header_offset)
881 header_offset = struct.pack("<L", header_offset)
882
883 local_extra = struct.pack(
884 '<HH' + 'Q'*len(local_zip64_fields),
885 0x0001,
886 8*len(local_zip64_fields),
887 *local_zip64_fields
888 )
889
890 central_extra = struct.pack(
891 '<HH' + 'Q'*len(central_zip64_fields),
892 0x0001,
893 8*len(central_zip64_fields),
894 *central_zip64_fields
895 )
896
897 central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
898 offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
899
900 local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
901 central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
902
903 filename = b"test.txt"
904 content = b"test1234"
905 filename_length = struct.pack("<H", len(filename))
906 zip64_contents = (
907 # Local file header
908 b"PK\x03\x04\x14\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
909 + compress_size
910 + file_size
911 + filename_length
912 + local_extra_length
913 + filename
914 + local_extra
915 + content
916 # Central directory:
917 + b"PK\x01\x02-\x03-\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
918 + compress_size
919 + file_size
920 + filename_length
921 + central_extra_length
922 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01"
923 + header_offset
924 + filename
925 + central_extra
926 # Zip64 end of central directory
927 + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
928 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
929 + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
930 + central_dir_size
931 + offset_to_central_dir
932 # Zip64 end of central directory locator
933 + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
934 + b"\x00\x00\x00"
935 # end of central directory
936 + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
937 + b"\x00\x00\x00\x00"
938 )
939 return zip64_contents
940
941 def test_bad_zip64_extra(self):
942 """Missing zip64 extra records raises an exception.
943
944 There are 4 fields that the zip64 format handles (the disk number is
945 not used in this module and so is ignored here). According to the zip
946 spec:
947 The order of the fields in the zip64 extended
948 information record is fixed, but the fields MUST
949 only appear if the corresponding Local or Central
950 directory record field is set to 0xFFFF or 0xFFFFFFFF.
951
952 If the zip64 extra content doesn't contain enough entries for the
953 number of fields marked with 0xFFFF or 0xFFFFFFFF, we raise an error.
954 This test mismatches the length of the zip64 extra field and the number
955 of fields set to indicate the presence of zip64 data.
956 """
957 # zip64 file size present, no fields in extra, expecting one, equals
958 # missing file size.
959 missing_file_size_extra = self.make_zip64_file(
960 file_size_64_set=True,
961 )
962 with self.assertRaises(zipfile.BadZipFile) as e:
963 zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
964 self.assertIn('file size', str(e.exception).lower())
965
966 # zip64 file size present, zip64 compress size present, one field in
967 # extra, expecting two, equals missing compress size.
968 missing_compress_size_extra = self.make_zip64_file(
969 file_size_64_set=True,
970 file_size_extra=True,
971 compress_size_64_set=True,
972 )
973 with self.assertRaises(zipfile.BadZipFile) as e:
974 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
975 self.assertIn('compress size', str(e.exception).lower())
976
977 # zip64 compress size present, no fields in extra, expecting one,
978 # equals missing compress size.
979 missing_compress_size_extra = self.make_zip64_file(
980 compress_size_64_set=True,
981 )
982 with self.assertRaises(zipfile.BadZipFile) as e:
983 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
984 self.assertIn('compress size', str(e.exception).lower())
985
986 # zip64 file size present, zip64 compress size present, zip64 header
987 # offset present, two fields in extra, expecting three, equals missing
988 # header offset
989 missing_header_offset_extra = self.make_zip64_file(
990 file_size_64_set=True,
991 file_size_extra=True,
992 compress_size_64_set=True,
993 compress_size_extra=True,
994 header_offset_64_set=True,
995 )
996 with self.assertRaises(zipfile.BadZipFile) as e:
997 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
998 self.assertIn('header offset', str(e.exception).lower())
999
1000 # zip64 compress size present, zip64 header offset present, one field
1001 # in extra, expecting two, equals missing header offset
1002 missing_header_offset_extra = self.make_zip64_file(
1003 file_size_64_set=False,
1004 compress_size_64_set=True,
1005 compress_size_extra=True,
1006 header_offset_64_set=True,
1007 )
1008 with self.assertRaises(zipfile.BadZipFile) as e:
1009 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1010 self.assertIn('header offset', str(e.exception).lower())
1011
1012 # zip64 file size present, zip64 header offset present, one field in
1013 # extra, expecting two, equals missing header offset
1014 missing_header_offset_extra = self.make_zip64_file(
1015 file_size_64_set=True,
1016 file_size_extra=True,
1017 compress_size_64_set=False,
1018 header_offset_64_set=True,
1019 )
1020 with self.assertRaises(zipfile.BadZipFile) as e:
1021 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1022 self.assertIn('header offset', str(e.exception).lower())
1023
1024 # zip64 header offset present, no fields in extra, expecting one,
1025 # equals missing header offset
1026 missing_header_offset_extra = self.make_zip64_file(
1027 file_size_64_set=False,
1028 compress_size_64_set=False,
1029 header_offset_64_set=True,
1030 )
1031 with self.assertRaises(zipfile.BadZipFile) as e:
1032 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1033 self.assertIn('header offset', str(e.exception).lower())
1034
1035 def test_generated_valid_zip64_extra(self):
1036 # These values are what is set in the make_zip64_file method.
1037 expected_file_size = 8
1038 expected_compress_size = 8
1039 expected_header_offset = 0
1040 expected_content = b"test1234"
1041
1042 # Loop through the various valid combinations of zip64 masks
1043 # present and extra fields present.
1044 params = (
1045 {"file_size_64_set": True, "file_size_extra": True},
1046 {"compress_size_64_set": True, "compress_size_extra": True},
1047 {"header_offset_64_set": True, "header_offset_extra": True},
1048 )
1049
1050 for r in range(1, len(params) + 1):
1051 for combo in itertools.combinations(params, r):
1052 kwargs = {}
1053 for c in combo:
1054 kwargs.update(c)
1055 with zipfile.ZipFile(io.BytesIO(self.make_zip64_file(**kwargs))) as zf:
1056 zinfo = zf.infolist()[0]
1057 self.assertEqual(zinfo.file_size, expected_file_size)
1058 self.assertEqual(zinfo.compress_size, expected_compress_size)
1059 self.assertEqual(zinfo.header_offset, expected_header_offset)
1060 self.assertEqual(zf.read(zinfo), expected_content)
1061
1062
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001063@requires_zlib
1064class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1065 unittest.TestCase):
1066 compression = zipfile.ZIP_DEFLATED
1067
1068@requires_bz2
1069class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1070 unittest.TestCase):
1071 compression = zipfile.ZIP_BZIP2
1072
1073@requires_lzma
1074class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1075 unittest.TestCase):
1076 compression = zipfile.ZIP_LZMA
1077
1078
Serhiy Storchaka4c0d9ea2017-04-12 16:03:23 +03001079class AbstractWriterTests:
1080
1081 def tearDown(self):
1082 unlink(TESTFN2)
1083
1084 def test_close_after_close(self):
1085 data = b'content'
1086 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1087 w = zipf.open('test', 'w')
1088 w.write(data)
1089 w.close()
1090 self.assertTrue(w.closed)
1091 w.close()
1092 self.assertTrue(w.closed)
1093 self.assertEqual(zipf.read('test'), data)
1094
1095 def test_write_after_close(self):
1096 data = b'content'
1097 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1098 w = zipf.open('test', 'w')
1099 w.write(data)
1100 w.close()
1101 self.assertTrue(w.closed)
1102 self.assertRaises(ValueError, w.write, b'')
1103 self.assertEqual(zipf.read('test'), data)
1104
1105class StoredWriterTests(AbstractWriterTests, unittest.TestCase):
1106 compression = zipfile.ZIP_STORED
1107
1108@requires_zlib
1109class DeflateWriterTests(AbstractWriterTests, unittest.TestCase):
1110 compression = zipfile.ZIP_DEFLATED
1111
1112@requires_bz2
1113class Bzip2WriterTests(AbstractWriterTests, unittest.TestCase):
1114 compression = zipfile.ZIP_BZIP2
1115
1116@requires_lzma
1117class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
1118 compression = zipfile.ZIP_LZMA
1119
1120
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001121class PyZipFileTests(unittest.TestCase):
1122 def assertCompiledIn(self, name, namelist):
1123 if name + 'o' not in namelist:
1124 self.assertIn(name + 'c', namelist)
1125
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001126 def requiresWriteAccess(self, path):
Berker Peksage1efc072015-02-16 04:36:18 +02001127 # effective_ids unavailable on windows
1128 if not os.access(path, os.W_OK,
1129 effective_ids=os.access in os.supports_effective_ids):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001130 self.skipTest('requires write access to the installed location')
Serhiy Storchakad86a6ef2015-09-19 10:55:20 +03001131 filename = os.path.join(path, 'test_zipfile.try')
1132 try:
1133 fd = os.open(filename, os.O_WRONLY | os.O_CREAT)
1134 os.close(fd)
1135 except Exception:
1136 self.skipTest('requires write access to the installed location')
1137 unlink(filename)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001138
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001139 def test_write_pyfile(self):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001140 self.requiresWriteAccess(os.path.dirname(__file__))
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001141 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1142 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001143 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001144 path_split = fn.split(os.sep)
1145 if os.altsep is not None:
1146 path_split.extend(fn.split(os.altsep))
1147 if '__pycache__' in path_split:
Serhiy Storchaka9068e4d2013-07-22 21:02:14 +03001148 fn = importlib.util.source_from_cache(fn)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001149 else:
1150 fn = fn[:-1]
1151
1152 zipfp.writepy(fn)
1153
1154 bn = os.path.basename(fn)
1155 self.assertNotIn(bn, zipfp.namelist())
1156 self.assertCompiledIn(bn, zipfp.namelist())
1157
1158 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 fn = fn[:-1]
1162
1163 zipfp.writepy(fn, "testpackage")
1164
1165 bn = "%s/%s" % ("testpackage", os.path.basename(fn))
1166 self.assertNotIn(bn, zipfp.namelist())
1167 self.assertCompiledIn(bn, zipfp.namelist())
1168
1169 def test_write_python_package(self):
1170 import email
1171 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001172 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001173
1174 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1175 zipfp.writepy(packagedir)
1176
1177 # Check for a couple of modules at different levels of the
1178 # hierarchy
1179 names = zipfp.namelist()
1180 self.assertCompiledIn('email/__init__.py', names)
1181 self.assertCompiledIn('email/mime/text.py', names)
1182
Christian Tismer59202e52013-10-21 03:59:23 +02001183 def test_write_filtered_python_package(self):
1184 import test
1185 packagedir = os.path.dirname(test.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001186 self.requiresWriteAccess(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001187
1188 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1189
Christian Tismer59202e52013-10-21 03:59:23 +02001190 # first make sure that the test folder gives error messages
Georg Brandla6065422013-10-21 08:29:29 +02001191 # (on the badsyntax_... files)
1192 with captured_stdout() as reportSIO:
1193 zipfp.writepy(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001194 reportStr = reportSIO.getvalue()
1195 self.assertTrue('SyntaxError' in reportStr)
1196
Christian Tismer410d9312013-10-22 04:09:28 +02001197 # then check that the filter works on the whole package
Georg Brandla6065422013-10-21 08:29:29 +02001198 with captured_stdout() as reportSIO:
1199 zipfp.writepy(packagedir, filterfunc=lambda whatever: False)
Christian Tismer59202e52013-10-21 03:59:23 +02001200 reportStr = reportSIO.getvalue()
1201 self.assertTrue('SyntaxError' not in reportStr)
1202
Christian Tismer410d9312013-10-22 04:09:28 +02001203 # then check that the filter works on individual files
Larry Hastings7e63b362015-05-08 06:54:58 -07001204 def filter(path):
1205 return not os.path.basename(path).startswith("bad")
Serhiy Storchakac46d1fa2014-01-20 21:59:33 +02001206 with captured_stdout() as reportSIO, self.assertWarns(UserWarning):
Larry Hastings7e63b362015-05-08 06:54:58 -07001207 zipfp.writepy(packagedir, filterfunc=filter)
Christian Tismer410d9312013-10-22 04:09:28 +02001208 reportStr = reportSIO.getvalue()
1209 if reportStr:
1210 print(reportStr)
1211 self.assertTrue('SyntaxError' not in reportStr)
1212
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001213 def test_write_with_optimization(self):
1214 import email
1215 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001216 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001217 optlevel = 1 if __debug__ else 0
Brett Cannonf299abd2015-04-13 14:21:02 -04001218 ext = '.pyc'
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001219
1220 with TemporaryFile() as t, \
Christian Tismer59202e52013-10-21 03:59:23 +02001221 zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001222 zipfp.writepy(packagedir)
1223
1224 names = zipfp.namelist()
1225 self.assertIn('email/__init__' + ext, names)
1226 self.assertIn('email/mime/text' + ext, names)
1227
1228 def test_write_python_directory(self):
1229 os.mkdir(TESTFN2)
1230 try:
1231 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1232 fp.write("print(42)\n")
1233
1234 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1235 fp.write("print(42 * 42)\n")
1236
1237 with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp:
1238 fp.write("bla bla bla\n")
1239
1240 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1241 zipfp.writepy(TESTFN2)
1242
1243 names = zipfp.namelist()
1244 self.assertCompiledIn('mod1.py', names)
1245 self.assertCompiledIn('mod2.py', names)
1246 self.assertNotIn('mod2.txt', names)
1247
1248 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001249 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001250
Christian Tismer410d9312013-10-22 04:09:28 +02001251 def test_write_python_directory_filtered(self):
1252 os.mkdir(TESTFN2)
1253 try:
1254 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1255 fp.write("print(42)\n")
1256
1257 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1258 fp.write("print(42 * 42)\n")
1259
1260 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1261 zipfp.writepy(TESTFN2, filterfunc=lambda fn:
1262 not fn.endswith('mod2.py'))
1263
1264 names = zipfp.namelist()
1265 self.assertCompiledIn('mod1.py', names)
1266 self.assertNotIn('mod2.py', names)
1267
1268 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001269 rmtree(TESTFN2)
Christian Tismer410d9312013-10-22 04:09:28 +02001270
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001271 def test_write_non_pyfile(self):
1272 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1273 with open(TESTFN, 'w') as f:
1274 f.write('most definitely not a python file')
1275 self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
Victor Stinner88b215e2014-09-04 00:51:09 +02001276 unlink(TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001277
1278 def test_write_pyfile_bad_syntax(self):
1279 os.mkdir(TESTFN2)
1280 try:
1281 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1282 fp.write("Bad syntax in python file\n")
1283
1284 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1285 # syntax errors are printed to stdout
1286 with captured_stdout() as s:
1287 zipfp.writepy(os.path.join(TESTFN2, "mod1.py"))
1288
1289 self.assertIn("SyntaxError", s.getvalue())
1290
1291 # as it will not have compiled the python file, it will
Brett Cannonf299abd2015-04-13 14:21:02 -04001292 # include the .py file not .pyc
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001293 names = zipfp.namelist()
1294 self.assertIn('mod1.py', names)
1295 self.assertNotIn('mod1.pyc', names)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001296
1297 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001298 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001299
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001300 def test_write_pathlike(self):
1301 os.mkdir(TESTFN2)
1302 try:
1303 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1304 fp.write("print(42)\n")
1305
1306 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1307 zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py")
1308 names = zipfp.namelist()
1309 self.assertCompiledIn('mod1.py', names)
1310 finally:
1311 rmtree(TESTFN2)
1312
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001313
1314class ExtractTests(unittest.TestCase):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001315
1316 def make_test_file(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001317 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1318 for fpath, fdata in SMALL_TEST_DATA:
1319 zipfp.writestr(fpath, fdata)
Christian Heimes790c8232008-01-07 21:14:23 +00001320
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001321 def test_extract(self):
1322 with temp_cwd():
1323 self.make_test_file()
1324 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1325 for fpath, fdata in SMALL_TEST_DATA:
1326 writtenfile = zipfp.extract(fpath)
1327
1328 # make sure it was written to the right place
1329 correctfile = os.path.join(os.getcwd(), fpath)
1330 correctfile = os.path.normpath(correctfile)
1331
1332 self.assertEqual(writtenfile, correctfile)
1333
1334 # make sure correct data is in correct file
1335 with open(writtenfile, "rb") as f:
1336 self.assertEqual(fdata.encode(), f.read())
1337
1338 unlink(writtenfile)
1339
1340 def _test_extract_with_target(self, target):
1341 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001342 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1343 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001344 writtenfile = zipfp.extract(fpath, target)
Christian Heimes790c8232008-01-07 21:14:23 +00001345
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001346 # make sure it was written to the right place
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001347 correctfile = os.path.join(target, fpath)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001348 correctfile = os.path.normpath(correctfile)
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001349 self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target))
Christian Heimes790c8232008-01-07 21:14:23 +00001350
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001351 # make sure correct data is in correct file
Brian Curtin8fb9b862010-11-18 02:15:28 +00001352 with open(writtenfile, "rb") as f:
1353 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001354
Victor Stinner88b215e2014-09-04 00:51:09 +02001355 unlink(writtenfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001356
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001357 unlink(TESTFN2)
1358
1359 def test_extract_with_target(self):
1360 with temp_dir() as extdir:
1361 self._test_extract_with_target(extdir)
1362
1363 def test_extract_with_target_pathlike(self):
1364 with temp_dir() as extdir:
1365 self._test_extract_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001366
Ezio Melottiafd0d112009-07-15 17:17:17 +00001367 def test_extract_all(self):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001368 with temp_cwd():
1369 self.make_test_file()
1370 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1371 zipfp.extractall()
1372 for fpath, fdata in SMALL_TEST_DATA:
1373 outfile = os.path.join(os.getcwd(), fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001374
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001375 with open(outfile, "rb") as f:
1376 self.assertEqual(fdata.encode(), f.read())
1377
1378 unlink(outfile)
1379
1380 def _test_extract_all_with_target(self, target):
1381 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001382 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001383 zipfp.extractall(target)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001384 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001385 outfile = os.path.join(target, fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001386
Brian Curtin8fb9b862010-11-18 02:15:28 +00001387 with open(outfile, "rb") as f:
1388 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001389
Victor Stinner88b215e2014-09-04 00:51:09 +02001390 unlink(outfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001391
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001392 unlink(TESTFN2)
1393
1394 def test_extract_all_with_target(self):
1395 with temp_dir() as extdir:
1396 self._test_extract_all_with_target(extdir)
1397
1398 def test_extract_all_with_target_pathlike(self):
1399 with temp_dir() as extdir:
1400 self._test_extract_all_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001401
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001402 def check_file(self, filename, content):
1403 self.assertTrue(os.path.isfile(filename))
1404 with open(filename, 'rb') as f:
1405 self.assertEqual(f.read(), content)
1406
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001407 def test_sanitize_windows_name(self):
1408 san = zipfile.ZipFile._sanitize_windows_name
1409 # Passing pathsep in allows this test to work regardless of platform.
1410 self.assertEqual(san(r',,?,C:,foo,bar/z', ','), r'_,C_,foo,bar/z')
1411 self.assertEqual(san(r'a\b,c<d>e|f"g?h*i', ','), r'a\b,c_d_e_f_g_h_i')
1412 self.assertEqual(san('../../foo../../ba..r', '/'), r'foo/ba..r')
1413
1414 def test_extract_hackers_arcnames_common_cases(self):
1415 common_hacknames = [
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001416 ('../foo/bar', 'foo/bar'),
1417 ('foo/../bar', 'foo/bar'),
1418 ('foo/../../bar', 'foo/bar'),
1419 ('foo/bar/..', 'foo/bar'),
1420 ('./../foo/bar', 'foo/bar'),
1421 ('/foo/bar', 'foo/bar'),
1422 ('/foo/../bar', 'foo/bar'),
1423 ('/foo/../../bar', 'foo/bar'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001424 ]
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001425 self._test_extract_hackers_arcnames(common_hacknames)
1426
1427 @unittest.skipIf(os.path.sep != '\\', 'Requires \\ as path separator.')
1428 def test_extract_hackers_arcnames_windows_only(self):
1429 """Test combination of path fixing and windows name sanitization."""
1430 windows_hacknames = [
Christian Tismer59202e52013-10-21 03:59:23 +02001431 (r'..\foo\bar', 'foo/bar'),
1432 (r'..\/foo\/bar', 'foo/bar'),
1433 (r'foo/\..\/bar', 'foo/bar'),
1434 (r'foo\/../\bar', 'foo/bar'),
1435 (r'C:foo/bar', 'foo/bar'),
1436 (r'C:/foo/bar', 'foo/bar'),
1437 (r'C://foo/bar', 'foo/bar'),
1438 (r'C:\foo\bar', 'foo/bar'),
1439 (r'//conky/mountpoint/foo/bar', 'foo/bar'),
1440 (r'\\conky\mountpoint\foo\bar', 'foo/bar'),
1441 (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1442 (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1443 (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1444 (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1445 (r'//?/C:/foo/bar', 'foo/bar'),
1446 (r'\\?\C:\foo\bar', 'foo/bar'),
1447 (r'C:/../C:/foo/bar', 'C_/foo/bar'),
1448 (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
1449 ('../../foo../../ba..r', 'foo/ba..r'),
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001450 ]
1451 self._test_extract_hackers_arcnames(windows_hacknames)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001452
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001453 @unittest.skipIf(os.path.sep != '/', r'Requires / as path separator.')
1454 def test_extract_hackers_arcnames_posix_only(self):
1455 posix_hacknames = [
1456 ('//foo/bar', 'foo/bar'),
1457 ('../../foo../../ba..r', 'foo../ba..r'),
1458 (r'foo/..\bar', r'foo/..\bar'),
1459 ]
1460 self._test_extract_hackers_arcnames(posix_hacknames)
1461
1462 def _test_extract_hackers_arcnames(self, hacknames):
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001463 for arcname, fixedname in hacknames:
1464 content = b'foobar' + arcname.encode()
1465 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001466 zinfo = zipfile.ZipInfo()
1467 # preserve backslashes
1468 zinfo.filename = arcname
1469 zinfo.external_attr = 0o600 << 16
1470 zipfp.writestr(zinfo, content)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001471
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001472 arcname = arcname.replace(os.sep, "/")
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001473 targetpath = os.path.join('target', 'subdir', 'subsub')
1474 correctfile = os.path.join(targetpath, *fixedname.split('/'))
1475
1476 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1477 writtenfile = zipfp.extract(arcname, targetpath)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001478 self.assertEqual(writtenfile, correctfile,
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001479 msg='extract %r: %r != %r' %
1480 (arcname, writtenfile, correctfile))
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001481 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001482 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001483
1484 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1485 zipfp.extractall(targetpath)
1486 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001487 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001488
1489 correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
1490
1491 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1492 writtenfile = zipfp.extract(arcname)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001493 self.assertEqual(writtenfile, correctfile,
1494 msg="extract %r" % arcname)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001495 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001496 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001497
1498 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1499 zipfp.extractall()
1500 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001501 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001502
Victor Stinner88b215e2014-09-04 00:51:09 +02001503 unlink(TESTFN2)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001504
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001505
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001506class OtherTests(unittest.TestCase):
1507 def test_open_via_zip_info(self):
1508 # Create the ZIP archive
1509 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1510 zipfp.writestr("name", "foo")
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001511 with self.assertWarns(UserWarning):
1512 zipfp.writestr("name", "bar")
1513 self.assertEqual(zipfp.namelist(), ["name"] * 2)
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001514
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001515 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1516 infos = zipfp.infolist()
1517 data = b""
1518 for info in infos:
1519 with zipfp.open(info) as zipopen:
1520 data += zipopen.read()
1521 self.assertIn(data, {b"foobar", b"barfoo"})
1522 data = b""
1523 for info in infos:
1524 data += zipfp.read(info)
1525 self.assertIn(data, {b"foobar", b"barfoo"})
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02001526
Gregory P. Smithb0d9ca922009-07-07 05:06:04 +00001527 def test_writestr_extended_local_header_issue1202(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001528 with zipfile.ZipFile(TESTFN2, 'w') as orig_zip:
1529 for data in 'abcdefghijklmnop':
1530 zinfo = zipfile.ZipInfo(data)
1531 zinfo.flag_bits |= 0x08 # Include an extended local header.
1532 orig_zip.writestr(zinfo, data)
1533
1534 def test_close(self):
1535 """Check that the zipfile is closed after the 'with' block."""
1536 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1537 for fpath, fdata in SMALL_TEST_DATA:
1538 zipfp.writestr(fpath, fdata)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001539 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1540 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001541
1542 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001543 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1544 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001545
1546 def test_close_on_exception(self):
1547 """Check that the zipfile is closed if an exception is raised in the
1548 'with' block."""
1549 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1550 for fpath, fdata in SMALL_TEST_DATA:
1551 zipfp.writestr(fpath, fdata)
1552
1553 try:
1554 with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
Georg Brandl4d540882010-10-28 06:42:33 +00001555 raise zipfile.BadZipFile()
1556 except zipfile.BadZipFile:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001557 self.assertIsNone(zipfp2.fp, 'zipfp is not closed')
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00001558
Martin v. Löwisd099b562012-05-01 14:08:22 +02001559 def test_unsupported_version(self):
1560 # File has an extract_version of 120
1561 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 +02001562 b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00xPK\x01\x02x\x03x\x00\x00\x00\x00'
1563 b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
1564 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06'
1565 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 +03001566
Martin v. Löwisd099b562012-05-01 14:08:22 +02001567 self.assertRaises(NotImplementedError, zipfile.ZipFile,
1568 io.BytesIO(data), 'r')
1569
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001570 @requires_zlib
1571 def test_read_unicode_filenames(self):
1572 # bug #10801
1573 fname = findfile('zip_cp437_header.zip')
1574 with zipfile.ZipFile(fname) as zipfp:
1575 for name in zipfp.namelist():
1576 zipfp.open(name).close()
1577
1578 def test_write_unicode_filenames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001579 with zipfile.ZipFile(TESTFN, "w") as zf:
1580 zf.writestr("foo.txt", "Test for unicode filename")
1581 zf.writestr("\xf6.txt", "Test for unicode filename")
Ezio Melottie9615932010-01-24 19:26:24 +00001582 self.assertIsInstance(zf.infolist()[0].filename, str)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001583
1584 with zipfile.ZipFile(TESTFN, "r") as zf:
1585 self.assertEqual(zf.filelist[0].filename, "foo.txt")
1586 self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
Martin v. Löwis8570f6a2008-05-05 17:44:38 +00001587
Serhiy Storchaka764fc9b2015-03-25 10:09:41 +02001588 def test_exclusive_create_zip_file(self):
1589 """Test exclusive creating a new zipfile."""
1590 unlink(TESTFN2)
1591 filename = 'testfile.txt'
1592 content = b'hello, world. this is some content.'
1593 with zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED) as zipfp:
1594 zipfp.writestr(filename, content)
1595 with self.assertRaises(FileExistsError):
1596 zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED)
1597 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1598 self.assertEqual(zipfp.namelist(), [filename])
1599 self.assertEqual(zipfp.read(filename), content)
1600
Ezio Melottiafd0d112009-07-15 17:17:17 +00001601 def test_create_non_existent_file_for_append(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00001602 if os.path.exists(TESTFN):
1603 os.unlink(TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001604
Thomas Wouterscf297e42007-02-23 15:07:44 +00001605 filename = 'testfile.txt'
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001606 content = b'hello, world. this is some content.'
Guido van Rossumd8faa362007-04-27 19:54:29 +00001607
Thomas Wouterscf297e42007-02-23 15:07:44 +00001608 try:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001609 with zipfile.ZipFile(TESTFN, 'a') as zf:
1610 zf.writestr(filename, content)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001611 except OSError:
Thomas Wouterscf297e42007-02-23 15:07:44 +00001612 self.fail('Could not append data to a non-existent zip file.')
1613
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001614 self.assertTrue(os.path.exists(TESTFN))
Thomas Wouterscf297e42007-02-23 15:07:44 +00001615
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001616 with zipfile.ZipFile(TESTFN, 'r') as zf:
1617 self.assertEqual(zf.read(filename), content)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001618
Ezio Melottiafd0d112009-07-15 17:17:17 +00001619 def test_close_erroneous_file(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001620 # This test checks that the ZipFile constructor closes the file object
Ezio Melotti35386712009-12-31 13:22:41 +00001621 # it opens if there's an error in the file. If it doesn't, the
1622 # traceback holds a reference to the ZipFile object and, indirectly,
1623 # the file object.
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001624 # On Windows, this causes the os.unlink() call to fail because the
1625 # underlying file is still open. This is SF bug #412214.
1626 #
Ezio Melotti35386712009-12-31 13:22:41 +00001627 with open(TESTFN, "w") as fp:
1628 fp.write("this is not a legal zip file\n")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001629 try:
1630 zf = zipfile.ZipFile(TESTFN)
Georg Brandl4d540882010-10-28 06:42:33 +00001631 except zipfile.BadZipFile:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001632 pass
1633
Ezio Melottiafd0d112009-07-15 17:17:17 +00001634 def test_is_zip_erroneous_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001635 """Check that is_zipfile() correctly identifies non-zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001636 # - passing a filename
1637 with open(TESTFN, "w") as fp:
1638 fp.write("this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001639 self.assertFalse(zipfile.is_zipfile(TESTFN))
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001640 # - passing a path-like object
1641 self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN)))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001642 # - passing a file object
1643 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001644 self.assertFalse(zipfile.is_zipfile(fp))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001645 # - passing a file-like object
1646 fp = io.BytesIO()
1647 fp.write(b"this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001648 self.assertFalse(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001649 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001650 self.assertFalse(zipfile.is_zipfile(fp))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001651
Serhiy Storchakad2b15272013-01-31 15:27:07 +02001652 def test_damaged_zipfile(self):
1653 """Check that zipfiles with missing bytes at the end raise BadZipFile."""
1654 # - Create a valid zip file
1655 fp = io.BytesIO()
1656 with zipfile.ZipFile(fp, mode="w") as zipf:
1657 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1658 zipfiledata = fp.getvalue()
1659
1660 # - Now create copies of it missing the last N bytes and make sure
1661 # a BadZipFile exception is raised when we try to open it
1662 for N in range(len(zipfiledata)):
1663 fp = io.BytesIO(zipfiledata[:N])
1664 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, fp)
1665
Ezio Melottiafd0d112009-07-15 17:17:17 +00001666 def test_is_zip_valid_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001667 """Check that is_zipfile() correctly identifies zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001668 # - passing a filename
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001669 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1670 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1671
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001672 self.assertTrue(zipfile.is_zipfile(TESTFN))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001673 # - passing a file object
1674 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001675 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001676 fp.seek(0, 0)
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001677 zip_contents = fp.read()
1678 # - passing a file-like object
1679 fp = io.BytesIO()
1680 fp.write(zip_contents)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001681 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001682 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001683 self.assertTrue(zipfile.is_zipfile(fp))
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001684
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001685 def test_non_existent_file_raises_OSError(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001686 # make sure we don't raise an AttributeError when a partially-constructed
1687 # ZipFile instance is finalized; this tests for regression on SF tracker
1688 # bug #403871.
1689
1690 # The bug we're testing for caused an AttributeError to be raised
1691 # when a ZipFile instance was created for a file that did not
1692 # exist; the .fp member was not initialized but was needed by the
1693 # __del__() method. Since the AttributeError is in the __del__(),
1694 # it is ignored, but the user should be sufficiently annoyed by
1695 # the message on the output that regression will be noticed
1696 # quickly.
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001697 self.assertRaises(OSError, zipfile.ZipFile, TESTFN)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001698
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001699 def test_empty_file_raises_BadZipFile(self):
1700 f = open(TESTFN, 'w')
1701 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001702 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001703
Ezio Melotti35386712009-12-31 13:22:41 +00001704 with open(TESTFN, 'w') as fp:
1705 fp.write("short file")
Georg Brandl4d540882010-10-28 06:42:33 +00001706 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001707
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001708 def test_closed_zip_raises_ValueError(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001709 """Verify that testzip() doesn't swallow inappropriate exceptions."""
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001710 data = io.BytesIO()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001711 with zipfile.ZipFile(data, mode="w") as zipf:
1712 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001713
Andrew Svetlov737fb892012-12-18 21:14:22 +02001714 # This is correct; calling .read on a closed ZipFile should raise
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001715 # a ValueError, and so should calling .testzip. An earlier
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001716 # version of .testzip would swallow this exception (and any other)
1717 # and report that the first file in the archive was corrupt.
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001718 self.assertRaises(ValueError, zipf.read, "foo.txt")
1719 self.assertRaises(ValueError, zipf.open, "foo.txt")
1720 self.assertRaises(ValueError, zipf.testzip)
1721 self.assertRaises(ValueError, zipf.writestr, "bogus.txt", "bogus")
Brian Curtin8fb9b862010-11-18 02:15:28 +00001722 with open(TESTFN, 'w') as f:
1723 f.write('zipfile test data')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001724 self.assertRaises(ValueError, zipf.write, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001725
Ezio Melottiafd0d112009-07-15 17:17:17 +00001726 def test_bad_constructor_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001727 """Check that bad modes passed to ZipFile constructor are caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001728 self.assertRaises(ValueError, zipfile.ZipFile, TESTFN, "q")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001729
Ezio Melottiafd0d112009-07-15 17:17:17 +00001730 def test_bad_open_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001731 """Check that bad modes passed to ZipFile.open are caught."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001732 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1733 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1734
1735 with zipfile.ZipFile(TESTFN, mode="r") as zipf:
Serhiy Storchakae670be22016-06-11 19:32:44 +03001736 # read the data to make sure the file is there
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001737 zipf.read("foo.txt")
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001738 self.assertRaises(ValueError, zipf.open, "foo.txt", "q")
Serhiy Storchakae670be22016-06-11 19:32:44 +03001739 # universal newlines support is removed
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001740 self.assertRaises(ValueError, zipf.open, "foo.txt", "U")
1741 self.assertRaises(ValueError, zipf.open, "foo.txt", "rU")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001742
Ezio Melottiafd0d112009-07-15 17:17:17 +00001743 def test_read0(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001744 """Check that calling read(0) on a ZipExtFile object returns an empty
1745 string and doesn't advance file pointer."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001746 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1747 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1748 # read the data to make sure the file is there
Brian Curtin8fb9b862010-11-18 02:15:28 +00001749 with zipf.open("foo.txt") as f:
1750 for i in range(FIXEDTEST_SIZE):
1751 self.assertEqual(f.read(0), b'')
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001752
Brian Curtin8fb9b862010-11-18 02:15:28 +00001753 self.assertEqual(f.read(), b"O, for a Muse of Fire!")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001754
Ezio Melottiafd0d112009-07-15 17:17:17 +00001755 def test_open_non_existent_item(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001756 """Check that attempting to call open() for an item that doesn't
1757 exist in the archive raises a RuntimeError."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001758 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1759 self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001760
Ezio Melottiafd0d112009-07-15 17:17:17 +00001761 def test_bad_compression_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001762 """Check that bad compression methods passed to ZipFile.open are
1763 caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001764 self.assertRaises(NotImplementedError, zipfile.ZipFile, TESTFN, "w", -1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001765
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001766 def test_unsupported_compression(self):
1767 # data is declared as shrunk, but actually deflated
1768 data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001769 b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
1770 b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
1771 b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1772 b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
1773 b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001774 with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
1775 self.assertRaises(NotImplementedError, zipf.open, 'x')
1776
Ezio Melottiafd0d112009-07-15 17:17:17 +00001777 def test_null_byte_in_filename(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001778 """Check that a filename containing a null byte is properly
1779 terminated."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001780 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1781 zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
1782 self.assertEqual(zipf.namelist(), ['foo.txt'])
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001783
Ezio Melottiafd0d112009-07-15 17:17:17 +00001784 def test_struct_sizes(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001785 """Check that ZIP internal structure sizes are calculated correctly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001786 self.assertEqual(zipfile.sizeEndCentDir, 22)
1787 self.assertEqual(zipfile.sizeCentralDir, 46)
1788 self.assertEqual(zipfile.sizeEndCentDir64, 56)
1789 self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
1790
Ezio Melottiafd0d112009-07-15 17:17:17 +00001791 def test_comments(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001792 """Check that comments on the archive are handled properly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001793
1794 # check default comment is empty
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001795 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1796 self.assertEqual(zipf.comment, b'')
1797 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1798
1799 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1800 self.assertEqual(zipfr.comment, b'')
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001801
1802 # check a simple short comment
1803 comment = b'Bravely taking to his feet, he beat a very brave retreat.'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001804 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1805 zipf.comment = comment
1806 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1807 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1808 self.assertEqual(zipf.comment, comment)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001809
1810 # check a comment of max length
1811 comment2 = ''.join(['%d' % (i**3 % 10) for i in range((1 << 16)-1)])
1812 comment2 = comment2.encode("ascii")
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001813 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1814 zipf.comment = comment2
1815 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1816
1817 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1818 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001819
1820 # check a comment that is too long is truncated
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001821 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001822 with self.assertWarns(UserWarning):
1823 zipf.comment = comment2 + b'oops'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001824 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1825 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1826 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001827
Antoine Pitrouc3991852012-06-30 17:31:37 +02001828 # check that comments are correctly modified in append mode
1829 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1830 zipf.comment = b"original comment"
1831 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1832 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1833 zipf.comment = b"an updated comment"
1834 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1835 self.assertEqual(zipf.comment, b"an updated comment")
1836
1837 # check that comments are correctly shortened in append mode
1838 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1839 zipf.comment = b"original comment that's longer"
1840 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1841 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1842 zipf.comment = b"shorter comment"
1843 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1844 self.assertEqual(zipf.comment, b"shorter comment")
1845
R David Murrayf50b38a2012-04-12 18:44:58 -04001846 def test_unicode_comment(self):
1847 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1848 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1849 with self.assertRaises(TypeError):
1850 zipf.comment = "this is an error"
1851
1852 def test_change_comment_in_empty_archive(self):
1853 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1854 self.assertFalse(zipf.filelist)
1855 zipf.comment = b"this is a comment"
1856 with zipfile.ZipFile(TESTFN, "r") as zipf:
1857 self.assertEqual(zipf.comment, b"this is a comment")
1858
1859 def test_change_comment_in_nonempty_archive(self):
1860 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1861 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1862 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1863 self.assertTrue(zipf.filelist)
1864 zipf.comment = b"this is a comment"
1865 with zipfile.ZipFile(TESTFN, "r") as zipf:
1866 self.assertEqual(zipf.comment, b"this is a comment")
1867
Georg Brandl268e4d42010-10-14 06:59:45 +00001868 def test_empty_zipfile(self):
1869 # Check that creating a file in 'w' or 'a' mode and closing without
1870 # adding any files to the archives creates a valid empty ZIP file
1871 zipf = zipfile.ZipFile(TESTFN, mode="w")
1872 zipf.close()
1873 try:
1874 zipf = zipfile.ZipFile(TESTFN, mode="r")
1875 except zipfile.BadZipFile:
1876 self.fail("Unable to create empty ZIP file in 'w' mode")
1877
1878 zipf = zipfile.ZipFile(TESTFN, mode="a")
1879 zipf.close()
1880 try:
1881 zipf = zipfile.ZipFile(TESTFN, mode="r")
1882 except:
1883 self.fail("Unable to create empty ZIP file in 'a' mode")
1884
1885 def test_open_empty_file(self):
1886 # Issue 1710703: Check that opening a file with less than 22 bytes
Georg Brandl4d540882010-10-28 06:42:33 +00001887 # raises a BadZipFile exception (rather than the previously unhelpful
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001888 # OSError)
Georg Brandl268e4d42010-10-14 06:59:45 +00001889 f = open(TESTFN, 'w')
1890 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001891 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN, 'r')
Georg Brandl268e4d42010-10-14 06:59:45 +00001892
Senthil Kumaran29fa9d42011-10-20 01:46:00 +08001893 def test_create_zipinfo_before_1980(self):
1894 self.assertRaises(ValueError,
1895 zipfile.ZipInfo, 'seventies', (1979, 1, 1, 0, 0, 0))
1896
Mickaël Schoentgen992347d2019-09-09 15:08:54 +02001897 def test_create_empty_zipinfo_repr(self):
1898 """Before bpo-26185, repr() on empty ZipInfo object was failing."""
1899 zi = zipfile.ZipInfo(filename="empty")
1900 self.assertEqual(repr(zi), "<ZipInfo filename='empty' file_size=0>")
1901
1902 def test_create_empty_zipinfo_default_attributes(self):
1903 """Ensure all required attributes are set."""
1904 zi = zipfile.ZipInfo()
1905 self.assertEqual(zi.orig_filename, "NoName")
1906 self.assertEqual(zi.filename, "NoName")
1907 self.assertEqual(zi.date_time, (1980, 1, 1, 0, 0, 0))
1908 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
1909 self.assertEqual(zi.comment, b"")
1910 self.assertEqual(zi.extra, b"")
1911 self.assertIn(zi.create_system, (0, 3))
1912 self.assertEqual(zi.create_version, zipfile.DEFAULT_VERSION)
1913 self.assertEqual(zi.extract_version, zipfile.DEFAULT_VERSION)
1914 self.assertEqual(zi.reserved, 0)
1915 self.assertEqual(zi.flag_bits, 0)
1916 self.assertEqual(zi.volume, 0)
1917 self.assertEqual(zi.internal_attr, 0)
1918 self.assertEqual(zi.external_attr, 0)
1919
1920 # Before bpo-26185, both were missing
1921 self.assertEqual(zi.file_size, 0)
1922 self.assertEqual(zi.compress_size, 0)
1923
Gregory P. Smith0af8a862014-05-29 23:42:14 -07001924 def test_zipfile_with_short_extra_field(self):
1925 """If an extra field in the header is less than 4 bytes, skip it."""
1926 zipdata = (
1927 b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1928 b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1929 b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1930 b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1931 b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1932 b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1933 b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1934 )
1935 with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1936 # testzip returns the name of the first corrupt file, or None
1937 self.assertIsNone(zipf.testzip())
1938
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001939 def test_open_conflicting_handles(self):
1940 # It's only possible to open one writable file handle at a time
1941 msg1 = b"It's fun to charter an accountant!"
1942 msg2 = b"And sail the wide accountant sea"
1943 msg3 = b"To find, explore the funds offshore"
1944 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
1945 with zipf.open('foo', mode='w') as w2:
1946 w2.write(msg1)
1947 with zipf.open('bar', mode='w') as w1:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001948 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001949 zipf.open('handle', mode='w')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001950 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001951 zipf.open('foo', mode='r')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001952 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001953 zipf.writestr('str', 'abcde')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001954 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001955 zipf.write(__file__, 'file')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001956 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001957 zipf.close()
1958 w1.write(msg2)
1959 with zipf.open('baz', mode='w') as w2:
1960 w2.write(msg3)
1961
1962 with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1963 self.assertEqual(zipf.read('foo'), msg1)
1964 self.assertEqual(zipf.read('bar'), msg2)
1965 self.assertEqual(zipf.read('baz'), msg3)
1966 self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
1967
John Jolly066df4f2018-01-30 01:51:35 -07001968 def test_seek_tell(self):
1969 # Test seek functionality
1970 txt = b"Where's Bruce?"
1971 bloc = txt.find(b"Bruce")
1972 # Check seek on a file
1973 with zipfile.ZipFile(TESTFN, "w") as zipf:
1974 zipf.writestr("foo.txt", txt)
1975 with zipfile.ZipFile(TESTFN, "r") as zipf:
1976 with zipf.open("foo.txt", "r") as fp:
1977 fp.seek(bloc, os.SEEK_SET)
1978 self.assertEqual(fp.tell(), bloc)
1979 fp.seek(-bloc, os.SEEK_CUR)
1980 self.assertEqual(fp.tell(), 0)
1981 fp.seek(bloc, os.SEEK_CUR)
1982 self.assertEqual(fp.tell(), bloc)
1983 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1984 fp.seek(0, os.SEEK_END)
1985 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001986 fp.seek(0, os.SEEK_SET)
1987 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07001988 # Check seek on memory file
1989 data = io.BytesIO()
1990 with zipfile.ZipFile(data, mode="w") as zipf:
1991 zipf.writestr("foo.txt", txt)
1992 with zipfile.ZipFile(data, mode="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
Berker Peksag2f1b8572019-09-12 17:13:44 +03002006 @requires_bz2
2007 def test_decompress_without_3rd_party_library(self):
2008 data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
2009 zip_file = io.BytesIO(data)
2010 with zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_BZIP2) as zf:
2011 zf.writestr('a.txt', b'a')
2012 with mock.patch('zipfile.bz2', None):
2013 with zipfile.ZipFile(zip_file) as zf:
2014 self.assertRaises(RuntimeError, zf.extract, 'a.txt')
2015
Guido van Rossumd8faa362007-04-27 19:54:29 +00002016 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002017 unlink(TESTFN)
2018 unlink(TESTFN2)
2019
Thomas Wouterscf297e42007-02-23 15:07:44 +00002020
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002021class AbstractBadCrcTests:
2022 def test_testzip_with_bad_crc(self):
2023 """Tests that files with bad CRCs return their name from testzip."""
2024 zipdata = self.zip_with_bad_crc
2025
2026 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2027 # testzip returns the name of the first corrupt file, or None
2028 self.assertEqual('afile', zipf.testzip())
2029
2030 def test_read_with_bad_crc(self):
2031 """Tests that files with bad CRCs raise a BadZipFile exception when read."""
2032 zipdata = self.zip_with_bad_crc
2033
2034 # Using ZipFile.read()
2035 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2036 self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile')
2037
2038 # Using ZipExtFile.read()
2039 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2040 with zipf.open('afile', 'r') as corrupt_file:
2041 self.assertRaises(zipfile.BadZipFile, corrupt_file.read)
2042
2043 # Same with small reads (in order to exercise the buffering logic)
2044 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2045 with zipf.open('afile', 'r') as corrupt_file:
2046 corrupt_file.MIN_READ_SIZE = 2
2047 with self.assertRaises(zipfile.BadZipFile):
2048 while corrupt_file.read(2):
2049 pass
2050
2051
2052class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2053 compression = zipfile.ZIP_STORED
2054 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002055 b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
2056 b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
2057 b'ilehello,AworldP'
2058 b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
2059 b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
2060 b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
2061 b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
2062 b'\0\0/\0\0\0\0\0')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002063
2064@requires_zlib
2065class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2066 compression = zipfile.ZIP_DEFLATED
2067 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002068 b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
2069 b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2070 b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
2071 b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
2072 b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
2073 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
2074 b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
2075 b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002076
2077@requires_bz2
2078class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2079 compression = zipfile.ZIP_BZIP2
2080 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002081 b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA'
2082 b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2083 b'ileBZh91AY&SY\xd4\xa8\xca'
2084 b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5'
2085 b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f'
2086 b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14'
2087 b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8'
2088 b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'
2089 b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK'
2090 b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00'
2091 b'\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002092
2093@requires_lzma
2094class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2095 compression = zipfile.ZIP_LZMA
2096 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002097 b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2098 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2099 b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I'
2100 b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK'
2101 b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2102 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00'
2103 b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil'
2104 b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
2105 b'\x00>\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002106
2107
Thomas Wouterscf297e42007-02-23 15:07:44 +00002108class DecryptionTests(unittest.TestCase):
Ezio Melotti35386712009-12-31 13:22:41 +00002109 """Check that ZIP decryption works. Since the library does not
2110 support encryption at the moment, we use a pre-generated encrypted
2111 ZIP file."""
Thomas Wouterscf297e42007-02-23 15:07:44 +00002112
2113 data = (
Christian Tismer59202e52013-10-21 03:59:23 +02002114 b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
2115 b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
2116 b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
2117 b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
2118 b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
2119 b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
2120 b'\x00\x00L\x00\x00\x00\x00\x00' )
Christian Heimesfdab48e2008-01-20 09:06:41 +00002121 data2 = (
Christian Tismer59202e52013-10-21 03:59:23 +02002122 b'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
2123 b'\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
2124 b'\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
2125 b'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
2126 b'\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
2127 b'\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
2128 b'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
2129 b'\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
Thomas Wouterscf297e42007-02-23 15:07:44 +00002130
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002131 plain = b'zipfile.py encryption test'
Christian Heimesfdab48e2008-01-20 09:06:41 +00002132 plain2 = b'\x00'*512
Thomas Wouterscf297e42007-02-23 15:07:44 +00002133
2134 def setUp(self):
Ezio Melotti35386712009-12-31 13:22:41 +00002135 with open(TESTFN, "wb") as fp:
2136 fp.write(self.data)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002137 self.zip = zipfile.ZipFile(TESTFN, "r")
Ezio Melotti35386712009-12-31 13:22:41 +00002138 with open(TESTFN2, "wb") as fp:
2139 fp.write(self.data2)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002140 self.zip2 = zipfile.ZipFile(TESTFN2, "r")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002141
2142 def tearDown(self):
2143 self.zip.close()
2144 os.unlink(TESTFN)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002145 self.zip2.close()
2146 os.unlink(TESTFN2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002147
Ezio Melottiafd0d112009-07-15 17:17:17 +00002148 def test_no_password(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00002149 # Reading the encrypted file without password
2150 # must generate a RunTime exception
2151 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002152 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002153
Ezio Melottiafd0d112009-07-15 17:17:17 +00002154 def test_bad_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002155 self.zip.setpassword(b"perl")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002156 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002157 self.zip2.setpassword(b"perl")
2158 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Guido van Rossumd8faa362007-04-27 19:54:29 +00002159
Ezio Melotti975077a2011-05-19 22:03:22 +03002160 @requires_zlib
Ezio Melottiafd0d112009-07-15 17:17:17 +00002161 def test_good_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002162 self.zip.setpassword(b"python")
Ezio Melotti35386712009-12-31 13:22:41 +00002163 self.assertEqual(self.zip.read("test.txt"), self.plain)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002164 self.zip2.setpassword(b"12345")
Ezio Melotti35386712009-12-31 13:22:41 +00002165 self.assertEqual(self.zip2.read("zero"), self.plain2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002166
R. David Murray8d855d82010-12-21 21:53:37 +00002167 def test_unicode_password(self):
2168 self.assertRaises(TypeError, self.zip.setpassword, "unicode")
2169 self.assertRaises(TypeError, self.zip.read, "test.txt", "python")
2170 self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python")
2171 self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python")
2172
Serhiy Storchaka5c32af72019-10-27 10:22:14 +02002173 def test_seek_tell(self):
2174 self.zip.setpassword(b"python")
2175 txt = self.plain
2176 test_word = b'encryption'
2177 bloc = txt.find(test_word)
2178 bloc_len = len(test_word)
2179 with self.zip.open("test.txt", "r") as fp:
2180 fp.seek(bloc, os.SEEK_SET)
2181 self.assertEqual(fp.tell(), bloc)
2182 fp.seek(-bloc, os.SEEK_CUR)
2183 self.assertEqual(fp.tell(), 0)
2184 fp.seek(bloc, os.SEEK_CUR)
2185 self.assertEqual(fp.tell(), bloc)
2186 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2187
2188 # Make sure that the second read after seeking back beyond
2189 # _readbuffer returns the same content (ie. rewind to the start of
2190 # the file to read forward to the required position).
2191 old_read_size = fp.MIN_READ_SIZE
2192 fp.MIN_READ_SIZE = 1
2193 fp._readbuffer = b''
2194 fp._offset = 0
2195 fp.seek(0, os.SEEK_SET)
2196 self.assertEqual(fp.tell(), 0)
2197 fp.seek(bloc, os.SEEK_CUR)
2198 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2199 fp.MIN_READ_SIZE = old_read_size
2200
2201 fp.seek(0, os.SEEK_END)
2202 self.assertEqual(fp.tell(), len(txt))
2203 fp.seek(0, os.SEEK_SET)
2204 self.assertEqual(fp.tell(), 0)
2205
2206 # Read the file completely to definitely call any eof integrity
2207 # checks (crc) and make sure they still pass.
2208 fp.read()
2209
2210
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002211class AbstractTestsWithRandomBinaryFiles:
2212 @classmethod
2213 def setUpClass(cls):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002214 datacount = randint(16, 64)*1024 + randint(1, 1024)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002215 cls.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
2216 for i in range(datacount))
Guido van Rossumd8faa362007-04-27 19:54:29 +00002217
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002218 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002219 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +00002220 with open(TESTFN, "wb") as fp:
2221 fp.write(self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002222
2223 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002224 unlink(TESTFN)
2225 unlink(TESTFN2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002226
Ezio Melottiafd0d112009-07-15 17:17:17 +00002227 def make_test_archive(self, f, compression):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002228 # Create the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002229 with zipfile.ZipFile(f, "w", compression) as zipfp:
2230 zipfp.write(TESTFN, "another.name")
2231 zipfp.write(TESTFN, TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002232
Ezio Melottiafd0d112009-07-15 17:17:17 +00002233 def zip_test(self, f, compression):
2234 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002235
2236 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002237 with zipfile.ZipFile(f, "r", compression) as zipfp:
2238 testdata = zipfp.read(TESTFN)
2239 self.assertEqual(len(testdata), len(self.data))
2240 self.assertEqual(testdata, self.data)
2241 self.assertEqual(zipfp.read("another.name"), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002242
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002243 def test_read(self):
2244 for f in get_files(self):
2245 self.zip_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002246
Ezio Melottiafd0d112009-07-15 17:17:17 +00002247 def zip_open_test(self, f, compression):
2248 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002249
2250 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002251 with zipfile.ZipFile(f, "r", compression) as zipfp:
2252 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002253 with zipfp.open(TESTFN) as zipopen1:
2254 while True:
2255 read_data = zipopen1.read(256)
2256 if not read_data:
2257 break
2258 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002259
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002260 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002261 with zipfp.open("another.name") as zipopen2:
2262 while True:
2263 read_data = zipopen2.read(256)
2264 if not read_data:
2265 break
2266 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002267
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002268 testdata1 = b''.join(zipdata1)
2269 self.assertEqual(len(testdata1), len(self.data))
2270 self.assertEqual(testdata1, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002271
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002272 testdata2 = b''.join(zipdata2)
Ezio Melotti35386712009-12-31 13:22:41 +00002273 self.assertEqual(len(testdata2), len(self.data))
2274 self.assertEqual(testdata2, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002275
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002276 def test_open(self):
2277 for f in get_files(self):
2278 self.zip_open_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002279
Ezio Melottiafd0d112009-07-15 17:17:17 +00002280 def zip_random_open_test(self, f, compression):
2281 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002282
2283 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002284 with zipfile.ZipFile(f, "r", compression) as zipfp:
2285 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002286 with zipfp.open(TESTFN) as zipopen1:
2287 while True:
2288 read_data = zipopen1.read(randint(1, 1024))
2289 if not read_data:
2290 break
2291 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002292
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002293 testdata = b''.join(zipdata1)
2294 self.assertEqual(len(testdata), len(self.data))
2295 self.assertEqual(testdata, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002296
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002297 def test_random_open(self):
2298 for f in get_files(self):
2299 self.zip_random_open_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002300
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00002301
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002302class StoredTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2303 unittest.TestCase):
2304 compression = zipfile.ZIP_STORED
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02002305
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002306@requires_zlib
2307class DeflateTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2308 unittest.TestCase):
2309 compression = zipfile.ZIP_DEFLATED
2310
2311@requires_bz2
2312class Bzip2TestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2313 unittest.TestCase):
2314 compression = zipfile.ZIP_BZIP2
2315
2316@requires_lzma
2317class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2318 unittest.TestCase):
2319 compression = zipfile.ZIP_LZMA
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002320
Ezio Melotti76430242009-07-11 18:28:48 +00002321
luzpaza5293b42017-11-05 07:37:50 -06002322# Provide the tell() method but not seek()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002323class Tellable:
2324 def __init__(self, fp):
2325 self.fp = fp
2326 self.offset = 0
2327
2328 def write(self, data):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002329 n = self.fp.write(data)
2330 self.offset += n
2331 return n
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002332
2333 def tell(self):
2334 return self.offset
2335
2336 def flush(self):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002337 self.fp.flush()
2338
2339class Unseekable:
2340 def __init__(self, fp):
2341 self.fp = fp
2342
2343 def write(self, data):
2344 return self.fp.write(data)
2345
2346 def flush(self):
2347 self.fp.flush()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002348
2349class UnseekableTests(unittest.TestCase):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002350 def test_writestr(self):
2351 for wrapper in (lambda f: f), Tellable, Unseekable:
2352 with self.subTest(wrapper=wrapper):
2353 f = io.BytesIO()
2354 f.write(b'abc')
2355 bf = io.BufferedWriter(f)
2356 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2357 zipfp.writestr('ones', b'111')
2358 zipfp.writestr('twos', b'222')
2359 self.assertEqual(f.getvalue()[:5], b'abcPK')
2360 with zipfile.ZipFile(f, mode='r') as zipf:
2361 with zipf.open('ones') as zopen:
2362 self.assertEqual(zopen.read(), b'111')
2363 with zipf.open('twos') as zopen:
2364 self.assertEqual(zopen.read(), b'222')
2365
2366 def test_write(self):
2367 for wrapper in (lambda f: f), Tellable, Unseekable:
2368 with self.subTest(wrapper=wrapper):
2369 f = io.BytesIO()
2370 f.write(b'abc')
2371 bf = io.BufferedWriter(f)
2372 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2373 self.addCleanup(unlink, TESTFN)
2374 with open(TESTFN, 'wb') as f2:
2375 f2.write(b'111')
2376 zipfp.write(TESTFN, 'ones')
2377 with open(TESTFN, 'wb') as f2:
2378 f2.write(b'222')
2379 zipfp.write(TESTFN, 'twos')
2380 self.assertEqual(f.getvalue()[:5], b'abcPK')
2381 with zipfile.ZipFile(f, mode='r') as zipf:
2382 with zipf.open('ones') as zopen:
2383 self.assertEqual(zopen.read(), b'111')
2384 with zipf.open('twos') as zopen:
2385 self.assertEqual(zopen.read(), b'222')
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002386
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002387 def test_open_write(self):
2388 for wrapper in (lambda f: f), Tellable, Unseekable:
2389 with self.subTest(wrapper=wrapper):
2390 f = io.BytesIO()
2391 f.write(b'abc')
2392 bf = io.BufferedWriter(f)
2393 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
2394 with zipf.open('ones', 'w') as zopen:
2395 zopen.write(b'111')
2396 with zipf.open('twos', 'w') as zopen:
2397 zopen.write(b'222')
2398 self.assertEqual(f.getvalue()[:5], b'abcPK')
2399 with zipfile.ZipFile(f) as zipf:
2400 self.assertEqual(zipf.read('ones'), b'111')
2401 self.assertEqual(zipf.read('twos'), b'222')
2402
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002403
Ezio Melotti975077a2011-05-19 22:03:22 +03002404@requires_zlib
Guido van Rossumd8faa362007-04-27 19:54:29 +00002405class TestsWithMultipleOpens(unittest.TestCase):
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002406 @classmethod
2407 def setUpClass(cls):
2408 cls.data1 = b'111' + getrandbytes(10000)
2409 cls.data2 = b'222' + getrandbytes(10000)
2410
2411 def make_test_archive(self, f):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002412 # Create the ZIP archive
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002413 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
2414 zipfp.writestr('ones', self.data1)
2415 zipfp.writestr('twos', self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002416
Ezio Melottiafd0d112009-07-15 17:17:17 +00002417 def test_same_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002418 # Verify that (when the ZipFile is in control of creating file objects)
2419 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002420 for f in get_files(self):
2421 self.make_test_archive(f)
2422 with zipfile.ZipFile(f, mode="r") as zipf:
2423 with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
2424 data1 = zopen1.read(500)
2425 data2 = zopen2.read(500)
2426 data1 += zopen1.read()
2427 data2 += zopen2.read()
2428 self.assertEqual(data1, data2)
2429 self.assertEqual(data1, self.data1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002430
Ezio Melottiafd0d112009-07-15 17:17:17 +00002431 def test_different_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002432 # Verify that (when the ZipFile is in control of creating file objects)
2433 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002434 for f in get_files(self):
2435 self.make_test_archive(f)
2436 with zipfile.ZipFile(f, mode="r") as zipf:
2437 with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
2438 data1 = zopen1.read(500)
2439 data2 = zopen2.read(500)
2440 data1 += zopen1.read()
2441 data2 += zopen2.read()
2442 self.assertEqual(data1, self.data1)
2443 self.assertEqual(data2, self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002444
Ezio Melottiafd0d112009-07-15 17:17:17 +00002445 def test_interleaved(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002446 # Verify that (when the ZipFile is in control of creating file objects)
2447 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002448 for f in get_files(self):
2449 self.make_test_archive(f)
2450 with zipfile.ZipFile(f, mode="r") as zipf:
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002451 with zipf.open('ones') as zopen1:
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002452 data1 = zopen1.read(500)
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002453 with zipf.open('twos') as zopen2:
2454 data2 = zopen2.read(500)
2455 data1 += zopen1.read()
2456 data2 += zopen2.read()
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002457 self.assertEqual(data1, self.data1)
2458 self.assertEqual(data2, self.data2)
2459
2460 def test_read_after_close(self):
2461 for f in get_files(self):
2462 self.make_test_archive(f)
2463 with contextlib.ExitStack() as stack:
2464 with zipfile.ZipFile(f, 'r') as zipf:
2465 zopen1 = stack.enter_context(zipf.open('ones'))
2466 zopen2 = stack.enter_context(zipf.open('twos'))
Brian Curtin8fb9b862010-11-18 02:15:28 +00002467 data1 = zopen1.read(500)
2468 data2 = zopen2.read(500)
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002469 data1 += zopen1.read()
2470 data2 += zopen2.read()
2471 self.assertEqual(data1, self.data1)
2472 self.assertEqual(data2, self.data2)
2473
2474 def test_read_after_write(self):
2475 for f in get_files(self):
2476 with zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as zipf:
2477 zipf.writestr('ones', self.data1)
2478 zipf.writestr('twos', self.data2)
2479 with zipf.open('ones') as zopen1:
2480 data1 = zopen1.read(500)
2481 self.assertEqual(data1, self.data1[:500])
2482 with zipfile.ZipFile(f, 'r') as zipf:
2483 data1 = zipf.read('ones')
2484 data2 = zipf.read('twos')
2485 self.assertEqual(data1, self.data1)
2486 self.assertEqual(data2, self.data2)
2487
2488 def test_write_after_read(self):
2489 for f in get_files(self):
2490 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipf:
2491 zipf.writestr('ones', self.data1)
2492 with zipf.open('ones') as zopen1:
2493 zopen1.read(500)
2494 zipf.writestr('twos', self.data2)
2495 with zipfile.ZipFile(f, 'r') as zipf:
2496 data1 = zipf.read('ones')
2497 data2 = zipf.read('twos')
2498 self.assertEqual(data1, self.data1)
2499 self.assertEqual(data2, self.data2)
2500
2501 def test_many_opens(self):
2502 # Verify that read() and open() promptly close the file descriptor,
2503 # and don't rely on the garbage collector to free resources.
2504 self.make_test_archive(TESTFN2)
2505 with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
2506 for x in range(100):
2507 zipf.read('ones')
2508 with zipf.open('ones') as zopen1:
2509 pass
2510 with open(os.devnull) as f:
2511 self.assertLess(f.fileno(), 100)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002512
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002513 def test_write_while_reading(self):
2514 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
2515 zipf.writestr('ones', self.data1)
2516 with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
2517 with zipf.open('ones', 'r') as r1:
2518 data1 = r1.read(500)
2519 with zipf.open('twos', 'w') as w1:
2520 w1.write(self.data2)
2521 data1 += r1.read()
2522 self.assertEqual(data1, self.data1)
2523 with zipfile.ZipFile(TESTFN2) as zipf:
2524 self.assertEqual(zipf.read('twos'), self.data2)
2525
Guido van Rossumd8faa362007-04-27 19:54:29 +00002526 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002527 unlink(TESTFN2)
2528
Guido van Rossumd8faa362007-04-27 19:54:29 +00002529
Martin v. Löwis59e47792009-01-24 14:10:07 +00002530class TestWithDirectory(unittest.TestCase):
2531 def setUp(self):
2532 os.mkdir(TESTFN2)
2533
Ezio Melottiafd0d112009-07-15 17:17:17 +00002534 def test_extract_dir(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002535 with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
2536 zipf.extractall(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002537 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
2538 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
2539 self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
2540
Ezio Melottiafd0d112009-07-15 17:17:17 +00002541 def test_bug_6050(self):
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002542 # Extraction should succeed if directories already exist
2543 os.mkdir(os.path.join(TESTFN2, "a"))
Ezio Melottiafd0d112009-07-15 17:17:17 +00002544 self.test_extract_dir()
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002545
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002546 def test_write_dir(self):
2547 dirpath = os.path.join(TESTFN2, "x")
2548 os.mkdir(dirpath)
2549 mode = os.stat(dirpath).st_mode & 0xFFFF
2550 with zipfile.ZipFile(TESTFN, "w") as zipf:
2551 zipf.write(dirpath)
2552 zinfo = zipf.filelist[0]
2553 self.assertTrue(zinfo.filename.endswith("/x/"))
2554 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2555 zipf.write(dirpath, "y")
2556 zinfo = zipf.filelist[1]
2557 self.assertTrue(zinfo.filename, "y/")
2558 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2559 with zipfile.ZipFile(TESTFN, "r") as zipf:
2560 zinfo = zipf.filelist[0]
2561 self.assertTrue(zinfo.filename.endswith("/x/"))
2562 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2563 zinfo = zipf.filelist[1]
2564 self.assertTrue(zinfo.filename, "y/")
2565 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2566 target = os.path.join(TESTFN2, "target")
2567 os.mkdir(target)
2568 zipf.extractall(target)
2569 self.assertTrue(os.path.isdir(os.path.join(target, "y")))
2570 self.assertEqual(len(os.listdir(target)), 2)
2571
2572 def test_writestr_dir(self):
Martin v. Löwis59e47792009-01-24 14:10:07 +00002573 os.mkdir(os.path.join(TESTFN2, "x"))
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002574 with zipfile.ZipFile(TESTFN, "w") as zipf:
2575 zipf.writestr("x/", b'')
2576 zinfo = zipf.filelist[0]
2577 self.assertEqual(zinfo.filename, "x/")
2578 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2579 with zipfile.ZipFile(TESTFN, "r") as zipf:
2580 zinfo = zipf.filelist[0]
2581 self.assertTrue(zinfo.filename.endswith("x/"))
2582 self.assertEqual(zinfo.external_attr, (0o40775 << 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, "x")))
2587 self.assertEqual(os.listdir(target), ["x"])
Martin v. Löwis59e47792009-01-24 14:10:07 +00002588
2589 def tearDown(self):
Victor Stinner57004c62014-09-04 00:49:01 +02002590 rmtree(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002591 if os.path.exists(TESTFN):
Ezio Melotti76430242009-07-11 18:28:48 +00002592 unlink(TESTFN)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002593
Guido van Rossumd8faa362007-04-27 19:54:29 +00002594
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002595class ZipInfoTests(unittest.TestCase):
2596 def test_from_file(self):
2597 zi = zipfile.ZipInfo.from_file(__file__)
2598 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2599 self.assertFalse(zi.is_dir())
Serhiy Storchaka8606e952017-03-08 14:37:51 +02002600 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2601
2602 def test_from_file_pathlike(self):
2603 zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
2604 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2605 self.assertFalse(zi.is_dir())
2606 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2607
2608 def test_from_file_bytes(self):
2609 zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
2610 self.assertEqual(posixpath.basename(zi.filename), 'test')
2611 self.assertFalse(zi.is_dir())
2612 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2613
2614 def test_from_file_fileno(self):
2615 with open(__file__, 'rb') as f:
2616 zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
2617 self.assertEqual(posixpath.basename(zi.filename), 'test')
2618 self.assertFalse(zi.is_dir())
2619 self.assertEqual(zi.file_size, os.path.getsize(__file__))
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002620
2621 def test_from_dir(self):
2622 dirpath = os.path.dirname(os.path.abspath(__file__))
2623 zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
2624 self.assertEqual(zi.filename, 'stdlib_tests/')
2625 self.assertTrue(zi.is_dir())
2626 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
2627 self.assertEqual(zi.file_size, 0)
2628
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002629
2630class CommandLineTest(unittest.TestCase):
2631
2632 def zipfilecmd(self, *args, **kwargs):
2633 rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args,
2634 **kwargs)
2635 return out.replace(os.linesep.encode(), b'\n')
2636
2637 def zipfilecmd_failure(self, *args):
2638 return script_helper.assert_python_failure('-m', 'zipfile', *args)
2639
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002640 def test_bad_use(self):
2641 rc, out, err = self.zipfilecmd_failure()
2642 self.assertEqual(out, b'')
2643 self.assertIn(b'usage', err.lower())
2644 self.assertIn(b'error', err.lower())
2645 self.assertIn(b'required', err.lower())
2646 rc, out, err = self.zipfilecmd_failure('-l', '')
2647 self.assertEqual(out, b'')
2648 self.assertNotEqual(err.strip(), b'')
2649
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002650 def test_test_command(self):
2651 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002652 for opt in '-t', '--test':
2653 out = self.zipfilecmd(opt, zip_name)
2654 self.assertEqual(out.rstrip(), b'Done testing')
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002655 zip_name = findfile('testtar.tar')
2656 rc, out, err = self.zipfilecmd_failure('-t', zip_name)
2657 self.assertEqual(out, b'')
2658
2659 def test_list_command(self):
2660 zip_name = findfile('zipdir.zip')
2661 t = io.StringIO()
2662 with zipfile.ZipFile(zip_name, 'r') as tf:
2663 tf.printdir(t)
2664 expected = t.getvalue().encode('ascii', 'backslashreplace')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002665 for opt in '-l', '--list':
2666 out = self.zipfilecmd(opt, zip_name,
2667 PYTHONIOENCODING='ascii:backslashreplace')
2668 self.assertEqual(out, expected)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002669
Serhiy Storchakab4293ef2016-10-23 22:32:30 +03002670 @requires_zlib
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002671 def test_create_command(self):
2672 self.addCleanup(unlink, TESTFN)
2673 with open(TESTFN, 'w') as f:
2674 f.write('test 1')
2675 os.mkdir(TESTFNDIR)
2676 self.addCleanup(rmtree, TESTFNDIR)
2677 with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f:
2678 f.write('test 2')
2679 files = [TESTFN, TESTFNDIR]
2680 namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt']
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002681 for opt in '-c', '--create':
2682 try:
2683 out = self.zipfilecmd(opt, TESTFN2, *files)
2684 self.assertEqual(out, b'')
2685 with zipfile.ZipFile(TESTFN2) as zf:
2686 self.assertEqual(zf.namelist(), namelist)
2687 self.assertEqual(zf.read(namelist[0]), b'test 1')
2688 self.assertEqual(zf.read(namelist[2]), b'test 2')
2689 finally:
2690 unlink(TESTFN2)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002691
2692 def test_extract_command(self):
2693 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002694 for opt in '-e', '--extract':
2695 with temp_dir() as extdir:
2696 out = self.zipfilecmd(opt, zip_name, extdir)
2697 self.assertEqual(out, b'')
2698 with zipfile.ZipFile(zip_name) as zf:
2699 for zi in zf.infolist():
2700 path = os.path.join(extdir,
2701 zi.filename.replace('/', os.sep))
2702 if zi.is_dir():
2703 self.assertTrue(os.path.isdir(path))
2704 else:
2705 self.assertTrue(os.path.isfile(path))
2706 with open(path, 'rb') as f:
2707 self.assertEqual(f.read(), zf.read(zi))
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002708
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002709
2710# Poor man's technique to consume a (smallish) iterable.
2711consume = tuple
2712
2713
shireenraoa4e29912019-08-24 11:26:41 -04002714def add_dirs(zf):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002715 """
shireenraoa4e29912019-08-24 11:26:41 -04002716 Given a writable zip file zf, inject directory entries for
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002717 any directories implied by the presence of children.
2718 """
shireenraoa4e29912019-08-24 11:26:41 -04002719 for name in zipfile.Path._implied_dirs(zf.namelist()):
2720 zf.writestr(name, b"")
2721 return zf
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002722
2723
shireenraoa4e29912019-08-24 11:26:41 -04002724def build_alpharep_fixture():
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002725 """
2726 Create a zip file with this structure:
2727
2728 .
2729 ├── a.txt
shireenraoa4e29912019-08-24 11:26:41 -04002730 ├── b
2731 │ ├── c.txt
2732 │ ├── d
2733 │ │ └── e.txt
2734 │ └── f.txt
2735 └── g
2736 └── h
2737 └── i.txt
2738
2739 This fixture has the following key characteristics:
2740
2741 - a file at the root (a)
2742 - a file two levels deep (b/d/e)
2743 - multiple files in a directory (b/c, b/f)
2744 - a directory containing only a directory (g/h)
2745
2746 "alpha" because it uses alphabet
2747 "rep" because it's a representative example
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002748 """
2749 data = io.BytesIO()
2750 zf = zipfile.ZipFile(data, "w")
2751 zf.writestr("a.txt", b"content of a")
2752 zf.writestr("b/c.txt", b"content of c")
2753 zf.writestr("b/d/e.txt", b"content of e")
shireenraoa4e29912019-08-24 11:26:41 -04002754 zf.writestr("b/f.txt", b"content of f")
2755 zf.writestr("g/h/i.txt", b"content of i")
2756 zf.filename = "alpharep.zip"
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002757 return zf
2758
2759
Gregory P. Smith3f4db4a2019-09-10 17:14:11 +01002760class TestExecutablePrependedZip(unittest.TestCase):
2761 """Test our ability to open zip files with an executable prepended."""
2762
2763 def setUp(self):
2764 self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
2765 self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
2766
2767 def _test_zip_works(self, name):
2768 # bpo-28494 sanity check: ensure is_zipfile works on these.
2769 self.assertTrue(zipfile.is_zipfile(name),
2770 f'is_zipfile failed on {name}')
2771 # Ensure we can operate on these via ZipFile.
2772 with zipfile.ZipFile(name) as zipfp:
2773 for n in zipfp.namelist():
2774 data = zipfp.read(n)
2775 self.assertIn(b'FAVORITE_NUMBER', data)
2776
2777 def test_read_zip_with_exe_prepended(self):
2778 self._test_zip_works(self.exe_zip)
2779
2780 def test_read_zip64_with_exe_prepended(self):
2781 self._test_zip_works(self.exe_zip64)
2782
2783 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2784 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2785 'Test relies on #!/bin/bash working.')
2786 def test_execute_zip2(self):
2787 output = subprocess.check_output([self.exe_zip, sys.executable])
2788 self.assertIn(b'number in executable: 5', output)
2789
2790 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2791 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2792 'Test relies on #!/bin/bash working.')
2793 def test_execute_zip64(self):
2794 output = subprocess.check_output([self.exe_zip64, sys.executable])
2795 self.assertIn(b'number in executable: 5', output)
2796
2797
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002798class TestPath(unittest.TestCase):
2799 def setUp(self):
2800 self.fixtures = contextlib.ExitStack()
2801 self.addCleanup(self.fixtures.close)
2802
shireenraoa4e29912019-08-24 11:26:41 -04002803 def zipfile_alpharep(self):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002804 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002805 yield build_alpharep_fixture()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002806 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002807 yield add_dirs(build_alpharep_fixture())
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002808
2809 def zipfile_ondisk(self):
2810 tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
shireenraoa4e29912019-08-24 11:26:41 -04002811 for alpharep in self.zipfile_alpharep():
2812 buffer = alpharep.fp
2813 alpharep.close()
2814 path = tmpdir / alpharep.filename
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002815 with path.open("wb") as strm:
2816 strm.write(buffer.getvalue())
2817 yield path
2818
shireenraoa4e29912019-08-24 11:26:41 -04002819 def test_iterdir_and_types(self):
2820 for alpharep in self.zipfile_alpharep():
2821 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002822 assert root.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002823 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002824 assert a.is_file()
2825 assert b.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002826 assert g.is_dir()
2827 c, f, d = b.iterdir()
2828 assert c.is_file() and f.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002829 e, = d.iterdir()
2830 assert e.is_file()
shireenraoa4e29912019-08-24 11:26:41 -04002831 h, = g.iterdir()
2832 i, = h.iterdir()
2833 assert i.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002834
2835 def test_open(self):
shireenraoa4e29912019-08-24 11:26:41 -04002836 for alpharep in self.zipfile_alpharep():
2837 root = zipfile.Path(alpharep)
2838 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002839 with a.open() as strm:
2840 data = strm.read()
2841 assert data == b"content of a"
2842
2843 def test_read(self):
shireenraoa4e29912019-08-24 11:26:41 -04002844 for alpharep in self.zipfile_alpharep():
2845 root = zipfile.Path(alpharep)
2846 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002847 assert a.read_text() == "content of a"
2848 assert a.read_bytes() == b"content of a"
2849
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002850 def test_joinpath(self):
shireenraoa4e29912019-08-24 11:26:41 -04002851 for alpharep in self.zipfile_alpharep():
2852 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002853 a = root.joinpath("a")
2854 assert a.is_file()
2855 e = root.joinpath("b").joinpath("d").joinpath("e.txt")
2856 assert e.read_text() == "content of e"
2857
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002858 def test_traverse_truediv(self):
shireenraoa4e29912019-08-24 11:26:41 -04002859 for alpharep in self.zipfile_alpharep():
2860 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002861 a = root / "a"
2862 assert a.is_file()
2863 e = root / "b" / "d" / "e.txt"
2864 assert e.read_text() == "content of e"
2865
2866 def test_pathlike_construction(self):
2867 """
2868 zipfile.Path should be constructable from a path-like object
2869 """
2870 for zipfile_ondisk in self.zipfile_ondisk():
2871 pathlike = pathlib.Path(str(zipfile_ondisk))
2872 zipfile.Path(pathlike)
2873
2874 def test_traverse_pathlike(self):
shireenraoa4e29912019-08-24 11:26:41 -04002875 for alpharep in self.zipfile_alpharep():
2876 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002877 root / pathlib.Path("a")
2878
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002879 def test_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002880 for alpharep in self.zipfile_alpharep():
2881 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002882 assert (root / 'a').parent.at == ''
2883 assert (root / 'a' / 'b').parent.at == 'a/'
2884
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002885 def test_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002886 for alpharep in self.zipfile_alpharep():
2887 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002888 assert (root / 'b').parent.at == ''
2889 assert (root / 'b/').parent.at == ''
2890
2891 def test_missing_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002892 for alpharep in self.zipfile_alpharep():
2893 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002894 assert (root / 'missing dir/').parent.at == ''
2895
shireenraoa4e29912019-08-24 11:26:41 -04002896
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00002897if __name__ == "__main__":
Brett Cannond5b4e1d2013-06-12 19:57:19 -04002898 unittest.main()