blob: 1e1854be7109b6ba52bb913027f707f85ccc6a74 [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
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300574 def test_write_to_readonly(self):
575 """Check that trying to call write() on a readonly ZipFile object
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300576 raises a ValueError."""
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300577 with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
578 zipfp.writestr("somefile.txt", "bogus")
579
580 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300581 self.assertRaises(ValueError, zipfp.write, TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300582
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300583 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300584 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300585 zipfp.open(TESTFN, mode='w')
586
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300587 def test_add_file_before_1980(self):
588 # Set atime and mtime to 1970-01-01
589 os.utime(TESTFN, (0, 0))
590 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
591 self.assertRaises(ValueError, zipfp.write, TESTFN)
592
Marcel Plch77b112c2018-08-31 16:43:31 +0200593 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
594 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200595 zinfo = zipfp.getinfo(TESTFN)
596 self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0))
597
598 def test_add_file_after_2107(self):
599 # Set atime and mtime to 2108-12-30
Marcel Plch7b41dba2018-08-03 17:59:19 +0200600 try:
601 os.utime(TESTFN, (4386268800, 4386268800))
602 except OverflowError:
603 self.skipTest('Host fs cannot set timestamp to required value.')
604
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200605 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
606 self.assertRaises(struct.error, zipfp.write, TESTFN)
607
Marcel Plch77b112c2018-08-31 16:43:31 +0200608 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
609 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200610 zinfo = zipfp.getinfo(TESTFN)
611 self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
612
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200613
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300614@requires_zlib
615class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,
616 unittest.TestCase):
617 compression = zipfile.ZIP_DEFLATED
618
Ezio Melottiafd0d112009-07-15 17:17:17 +0000619 def test_per_file_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000620 """Check that files within a Zip archive can have different
621 compression options."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000622 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
623 zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
624 zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
625 sinfo = zipfp.getinfo('storeme')
626 dinfo = zipfp.getinfo('deflateme')
627 self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
628 self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000629
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300630@requires_bz2
631class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile,
632 unittest.TestCase):
633 compression = zipfile.ZIP_BZIP2
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000634
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300635@requires_lzma
636class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile,
637 unittest.TestCase):
638 compression = zipfile.ZIP_LZMA
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000639
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300640
641class AbstractTestZip64InSmallFiles:
642 # These tests test the ZIP64 functionality without using large files,
643 # see test_zipfile64 for proper tests.
644
645 @classmethod
646 def setUpClass(cls):
647 line_gen = (bytes("Test of zipfile line %d." % i, "ascii")
648 for i in range(0, FIXEDTEST_SIZE))
649 cls.data = b'\n'.join(line_gen)
650
651 def setUp(self):
652 self._limit = zipfile.ZIP64_LIMIT
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300653 self._filecount_limit = zipfile.ZIP_FILECOUNT_LIMIT
654 zipfile.ZIP64_LIMIT = 1000
655 zipfile.ZIP_FILECOUNT_LIMIT = 9
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300656
657 # Make a source file with some lines
658 with open(TESTFN, "wb") as fp:
659 fp.write(self.data)
660
661 def zip_test(self, f, compression):
662 # Create the ZIP archive
663 with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
664 zipfp.write(TESTFN, "another.name")
665 zipfp.write(TESTFN, TESTFN)
666 zipfp.writestr("strfile", self.data)
667
668 # Read the ZIP archive
669 with zipfile.ZipFile(f, "r", compression) as zipfp:
670 self.assertEqual(zipfp.read(TESTFN), self.data)
671 self.assertEqual(zipfp.read("another.name"), self.data)
672 self.assertEqual(zipfp.read("strfile"), self.data)
673
674 # Print the ZIP directory
675 fp = io.StringIO()
676 zipfp.printdir(fp)
677
678 directory = fp.getvalue()
679 lines = directory.splitlines()
680 self.assertEqual(len(lines), 4) # Number of files + header
681
682 self.assertIn('File Name', lines[0])
683 self.assertIn('Modified', lines[0])
684 self.assertIn('Size', lines[0])
685
686 fn, date, time_, size = lines[1].split()
687 self.assertEqual(fn, 'another.name')
688 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
689 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
690 self.assertEqual(size, str(len(self.data)))
691
692 # Check the namelist
693 names = zipfp.namelist()
694 self.assertEqual(len(names), 3)
695 self.assertIn(TESTFN, names)
696 self.assertIn("another.name", names)
697 self.assertIn("strfile", names)
698
699 # Check infolist
700 infos = zipfp.infolist()
701 names = [i.filename for i in infos]
702 self.assertEqual(len(names), 3)
703 self.assertIn(TESTFN, names)
704 self.assertIn("another.name", names)
705 self.assertIn("strfile", names)
706 for i in infos:
707 self.assertEqual(i.file_size, len(self.data))
708
709 # check getinfo
710 for nm in (TESTFN, "another.name", "strfile"):
711 info = zipfp.getinfo(nm)
712 self.assertEqual(info.filename, nm)
713 self.assertEqual(info.file_size, len(self.data))
714
715 # Check that testzip doesn't raise an exception
716 zipfp.testzip()
717
718 def test_basic(self):
719 for f in get_files(self):
720 self.zip_test(f, self.compression)
721
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300722 def test_too_many_files(self):
723 # This test checks that more than 64k files can be added to an archive,
724 # and that the resulting archive can be read properly by ZipFile
725 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
726 allowZip64=True)
727 zipf.debug = 100
728 numfiles = 15
729 for i in range(numfiles):
730 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
731 self.assertEqual(len(zipf.namelist()), numfiles)
732 zipf.close()
733
734 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
735 self.assertEqual(len(zipf2.namelist()), numfiles)
736 for i in range(numfiles):
737 content = zipf2.read("foo%08d" % i).decode('ascii')
738 self.assertEqual(content, "%d" % (i**3 % 57))
739 zipf2.close()
740
741 def test_too_many_files_append(self):
742 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
743 allowZip64=False)
744 zipf.debug = 100
745 numfiles = 9
746 for i in range(numfiles):
747 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
748 self.assertEqual(len(zipf.namelist()), numfiles)
749 with self.assertRaises(zipfile.LargeZipFile):
750 zipf.writestr("foo%08d" % numfiles, b'')
751 self.assertEqual(len(zipf.namelist()), numfiles)
752 zipf.close()
753
754 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
755 allowZip64=False)
756 zipf.debug = 100
757 self.assertEqual(len(zipf.namelist()), numfiles)
758 with self.assertRaises(zipfile.LargeZipFile):
759 zipf.writestr("foo%08d" % numfiles, b'')
760 self.assertEqual(len(zipf.namelist()), numfiles)
761 zipf.close()
762
763 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
764 allowZip64=True)
765 zipf.debug = 100
766 self.assertEqual(len(zipf.namelist()), numfiles)
767 numfiles2 = 15
768 for i in range(numfiles, numfiles2):
769 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
770 self.assertEqual(len(zipf.namelist()), numfiles2)
771 zipf.close()
772
773 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
774 self.assertEqual(len(zipf2.namelist()), numfiles2)
775 for i in range(numfiles2):
776 content = zipf2.read("foo%08d" % i).decode('ascii')
777 self.assertEqual(content, "%d" % (i**3 % 57))
778 zipf2.close()
779
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300780 def tearDown(self):
781 zipfile.ZIP64_LIMIT = self._limit
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300782 zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300783 unlink(TESTFN)
784 unlink(TESTFN2)
785
786
787class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
788 unittest.TestCase):
789 compression = zipfile.ZIP_STORED
790
791 def large_file_exception_test(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200792 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300793 self.assertRaises(zipfile.LargeZipFile,
794 zipfp.write, TESTFN, "another.name")
795
796 def large_file_exception_test2(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200797 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300798 self.assertRaises(zipfile.LargeZipFile,
799 zipfp.writestr, "another.name", self.data)
800
801 def test_large_file_exception(self):
802 for f in get_files(self):
803 self.large_file_exception_test(f, zipfile.ZIP_STORED)
804 self.large_file_exception_test2(f, zipfile.ZIP_STORED)
805
806 def test_absolute_arcnames(self):
807 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
808 allowZip64=True) as zipfp:
809 zipfp.write(TESTFN, "/absolute")
810
811 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
812 self.assertEqual(zipfp.namelist(), ["absolute"])
813
Serhiy Storchaka9bdb7be2018-09-17 15:36:40 +0300814 def test_append(self):
815 # Test that appending to the Zip64 archive doesn't change
816 # extra fields of existing entries.
817 with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp:
818 zipfp.writestr("strfile", self.data)
819 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
820 zinfo = zipfp.getinfo("strfile")
821 extra = zinfo.extra
822 with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp:
823 zipfp.writestr("strfile2", self.data)
824 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
825 zinfo = zipfp.getinfo("strfile")
826 self.assertEqual(zinfo.extra, extra)
827
Daniel Hillierda6ce582019-10-29 18:24:18 +1100828 def make_zip64_file(
829 self, file_size_64_set=False, file_size_extra=False,
830 compress_size_64_set=False, compress_size_extra=False,
831 header_offset_64_set=False, header_offset_extra=False,
832 ):
833 """Generate bytes sequence for a zip with (incomplete) zip64 data.
834
835 The actual values (not the zip 64 0xffffffff values) stored in the file
836 are:
837 file_size: 8
838 compress_size: 8
839 header_offset: 0
840 """
841 actual_size = 8
842 actual_header_offset = 0
843 local_zip64_fields = []
844 central_zip64_fields = []
845
846 file_size = actual_size
847 if file_size_64_set:
848 file_size = 0xffffffff
849 if file_size_extra:
850 local_zip64_fields.append(actual_size)
851 central_zip64_fields.append(actual_size)
852 file_size = struct.pack("<L", file_size)
853
854 compress_size = actual_size
855 if compress_size_64_set:
856 compress_size = 0xffffffff
857 if compress_size_extra:
858 local_zip64_fields.append(actual_size)
859 central_zip64_fields.append(actual_size)
860 compress_size = struct.pack("<L", compress_size)
861
862 header_offset = actual_header_offset
863 if header_offset_64_set:
864 header_offset = 0xffffffff
865 if header_offset_extra:
866 central_zip64_fields.append(actual_header_offset)
867 header_offset = struct.pack("<L", header_offset)
868
869 local_extra = struct.pack(
870 '<HH' + 'Q'*len(local_zip64_fields),
871 0x0001,
872 8*len(local_zip64_fields),
873 *local_zip64_fields
874 )
875
876 central_extra = struct.pack(
877 '<HH' + 'Q'*len(central_zip64_fields),
878 0x0001,
879 8*len(central_zip64_fields),
880 *central_zip64_fields
881 )
882
883 central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
884 offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
885
886 local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
887 central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
888
889 filename = b"test.txt"
890 content = b"test1234"
891 filename_length = struct.pack("<H", len(filename))
892 zip64_contents = (
893 # Local file header
894 b"PK\x03\x04\x14\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
895 + compress_size
896 + file_size
897 + filename_length
898 + local_extra_length
899 + filename
900 + local_extra
901 + content
902 # Central directory:
903 + b"PK\x01\x02-\x03-\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
904 + compress_size
905 + file_size
906 + filename_length
907 + central_extra_length
908 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01"
909 + header_offset
910 + filename
911 + central_extra
912 # Zip64 end of central directory
913 + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
914 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
915 + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
916 + central_dir_size
917 + offset_to_central_dir
918 # Zip64 end of central directory locator
919 + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
920 + b"\x00\x00\x00"
921 # end of central directory
922 + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
923 + b"\x00\x00\x00\x00"
924 )
925 return zip64_contents
926
927 def test_bad_zip64_extra(self):
928 """Missing zip64 extra records raises an exception.
929
930 There are 4 fields that the zip64 format handles (the disk number is
931 not used in this module and so is ignored here). According to the zip
932 spec:
933 The order of the fields in the zip64 extended
934 information record is fixed, but the fields MUST
935 only appear if the corresponding Local or Central
936 directory record field is set to 0xFFFF or 0xFFFFFFFF.
937
938 If the zip64 extra content doesn't contain enough entries for the
939 number of fields marked with 0xFFFF or 0xFFFFFFFF, we raise an error.
940 This test mismatches the length of the zip64 extra field and the number
941 of fields set to indicate the presence of zip64 data.
942 """
943 # zip64 file size present, no fields in extra, expecting one, equals
944 # missing file size.
945 missing_file_size_extra = self.make_zip64_file(
946 file_size_64_set=True,
947 )
948 with self.assertRaises(zipfile.BadZipFile) as e:
949 zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
950 self.assertIn('file size', str(e.exception).lower())
951
952 # zip64 file size present, zip64 compress size present, one field in
953 # extra, expecting two, equals missing compress size.
954 missing_compress_size_extra = self.make_zip64_file(
955 file_size_64_set=True,
956 file_size_extra=True,
957 compress_size_64_set=True,
958 )
959 with self.assertRaises(zipfile.BadZipFile) as e:
960 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
961 self.assertIn('compress size', str(e.exception).lower())
962
963 # zip64 compress size present, no fields in extra, expecting one,
964 # equals missing compress size.
965 missing_compress_size_extra = self.make_zip64_file(
966 compress_size_64_set=True,
967 )
968 with self.assertRaises(zipfile.BadZipFile) as e:
969 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
970 self.assertIn('compress size', str(e.exception).lower())
971
972 # zip64 file size present, zip64 compress size present, zip64 header
973 # offset present, two fields in extra, expecting three, equals missing
974 # header offset
975 missing_header_offset_extra = self.make_zip64_file(
976 file_size_64_set=True,
977 file_size_extra=True,
978 compress_size_64_set=True,
979 compress_size_extra=True,
980 header_offset_64_set=True,
981 )
982 with self.assertRaises(zipfile.BadZipFile) as e:
983 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
984 self.assertIn('header offset', str(e.exception).lower())
985
986 # zip64 compress size present, zip64 header offset present, one field
987 # in extra, expecting two, equals missing header offset
988 missing_header_offset_extra = self.make_zip64_file(
989 file_size_64_set=False,
990 compress_size_64_set=True,
991 compress_size_extra=True,
992 header_offset_64_set=True,
993 )
994 with self.assertRaises(zipfile.BadZipFile) as e:
995 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
996 self.assertIn('header offset', str(e.exception).lower())
997
998 # zip64 file size present, zip64 header offset present, one field in
999 # extra, expecting two, equals missing header offset
1000 missing_header_offset_extra = self.make_zip64_file(
1001 file_size_64_set=True,
1002 file_size_extra=True,
1003 compress_size_64_set=False,
1004 header_offset_64_set=True,
1005 )
1006 with self.assertRaises(zipfile.BadZipFile) as e:
1007 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1008 self.assertIn('header offset', str(e.exception).lower())
1009
1010 # zip64 header offset present, no fields in extra, expecting one,
1011 # equals missing header offset
1012 missing_header_offset_extra = self.make_zip64_file(
1013 file_size_64_set=False,
1014 compress_size_64_set=False,
1015 header_offset_64_set=True,
1016 )
1017 with self.assertRaises(zipfile.BadZipFile) as e:
1018 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1019 self.assertIn('header offset', str(e.exception).lower())
1020
1021 def test_generated_valid_zip64_extra(self):
1022 # These values are what is set in the make_zip64_file method.
1023 expected_file_size = 8
1024 expected_compress_size = 8
1025 expected_header_offset = 0
1026 expected_content = b"test1234"
1027
1028 # Loop through the various valid combinations of zip64 masks
1029 # present and extra fields present.
1030 params = (
1031 {"file_size_64_set": True, "file_size_extra": True},
1032 {"compress_size_64_set": True, "compress_size_extra": True},
1033 {"header_offset_64_set": True, "header_offset_extra": True},
1034 )
1035
1036 for r in range(1, len(params) + 1):
1037 for combo in itertools.combinations(params, r):
1038 kwargs = {}
1039 for c in combo:
1040 kwargs.update(c)
1041 with zipfile.ZipFile(io.BytesIO(self.make_zip64_file(**kwargs))) as zf:
1042 zinfo = zf.infolist()[0]
1043 self.assertEqual(zinfo.file_size, expected_file_size)
1044 self.assertEqual(zinfo.compress_size, expected_compress_size)
1045 self.assertEqual(zinfo.header_offset, expected_header_offset)
1046 self.assertEqual(zf.read(zinfo), expected_content)
1047
1048
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001049@requires_zlib
1050class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1051 unittest.TestCase):
1052 compression = zipfile.ZIP_DEFLATED
1053
1054@requires_bz2
1055class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1056 unittest.TestCase):
1057 compression = zipfile.ZIP_BZIP2
1058
1059@requires_lzma
1060class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1061 unittest.TestCase):
1062 compression = zipfile.ZIP_LZMA
1063
1064
Serhiy Storchaka4c0d9ea2017-04-12 16:03:23 +03001065class AbstractWriterTests:
1066
1067 def tearDown(self):
1068 unlink(TESTFN2)
1069
1070 def test_close_after_close(self):
1071 data = b'content'
1072 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1073 w = zipf.open('test', 'w')
1074 w.write(data)
1075 w.close()
1076 self.assertTrue(w.closed)
1077 w.close()
1078 self.assertTrue(w.closed)
1079 self.assertEqual(zipf.read('test'), data)
1080
1081 def test_write_after_close(self):
1082 data = b'content'
1083 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1084 w = zipf.open('test', 'w')
1085 w.write(data)
1086 w.close()
1087 self.assertTrue(w.closed)
1088 self.assertRaises(ValueError, w.write, b'')
1089 self.assertEqual(zipf.read('test'), data)
1090
1091class StoredWriterTests(AbstractWriterTests, unittest.TestCase):
1092 compression = zipfile.ZIP_STORED
1093
1094@requires_zlib
1095class DeflateWriterTests(AbstractWriterTests, unittest.TestCase):
1096 compression = zipfile.ZIP_DEFLATED
1097
1098@requires_bz2
1099class Bzip2WriterTests(AbstractWriterTests, unittest.TestCase):
1100 compression = zipfile.ZIP_BZIP2
1101
1102@requires_lzma
1103class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
1104 compression = zipfile.ZIP_LZMA
1105
1106
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001107class PyZipFileTests(unittest.TestCase):
1108 def assertCompiledIn(self, name, namelist):
1109 if name + 'o' not in namelist:
1110 self.assertIn(name + 'c', namelist)
1111
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001112 def requiresWriteAccess(self, path):
Berker Peksage1efc072015-02-16 04:36:18 +02001113 # effective_ids unavailable on windows
1114 if not os.access(path, os.W_OK,
1115 effective_ids=os.access in os.supports_effective_ids):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001116 self.skipTest('requires write access to the installed location')
Serhiy Storchakad86a6ef2015-09-19 10:55:20 +03001117 filename = os.path.join(path, 'test_zipfile.try')
1118 try:
1119 fd = os.open(filename, os.O_WRONLY | os.O_CREAT)
1120 os.close(fd)
1121 except Exception:
1122 self.skipTest('requires write access to the installed location')
1123 unlink(filename)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001124
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001125 def test_write_pyfile(self):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001126 self.requiresWriteAccess(os.path.dirname(__file__))
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001127 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1128 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001129 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001130 path_split = fn.split(os.sep)
1131 if os.altsep is not None:
1132 path_split.extend(fn.split(os.altsep))
1133 if '__pycache__' in path_split:
Serhiy Storchaka9068e4d2013-07-22 21:02:14 +03001134 fn = importlib.util.source_from_cache(fn)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001135 else:
1136 fn = fn[:-1]
1137
1138 zipfp.writepy(fn)
1139
1140 bn = os.path.basename(fn)
1141 self.assertNotIn(bn, zipfp.namelist())
1142 self.assertCompiledIn(bn, zipfp.namelist())
1143
1144 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1145 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001146 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001147 fn = fn[:-1]
1148
1149 zipfp.writepy(fn, "testpackage")
1150
1151 bn = "%s/%s" % ("testpackage", os.path.basename(fn))
1152 self.assertNotIn(bn, zipfp.namelist())
1153 self.assertCompiledIn(bn, zipfp.namelist())
1154
1155 def test_write_python_package(self):
1156 import email
1157 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001158 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001159
1160 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1161 zipfp.writepy(packagedir)
1162
1163 # Check for a couple of modules at different levels of the
1164 # hierarchy
1165 names = zipfp.namelist()
1166 self.assertCompiledIn('email/__init__.py', names)
1167 self.assertCompiledIn('email/mime/text.py', names)
1168
Christian Tismer59202e52013-10-21 03:59:23 +02001169 def test_write_filtered_python_package(self):
1170 import test
1171 packagedir = os.path.dirname(test.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001172 self.requiresWriteAccess(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001173
1174 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1175
Christian Tismer59202e52013-10-21 03:59:23 +02001176 # first make sure that the test folder gives error messages
Georg Brandla6065422013-10-21 08:29:29 +02001177 # (on the badsyntax_... files)
1178 with captured_stdout() as reportSIO:
1179 zipfp.writepy(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001180 reportStr = reportSIO.getvalue()
1181 self.assertTrue('SyntaxError' in reportStr)
1182
Christian Tismer410d9312013-10-22 04:09:28 +02001183 # then check that the filter works on the whole package
Georg Brandla6065422013-10-21 08:29:29 +02001184 with captured_stdout() as reportSIO:
1185 zipfp.writepy(packagedir, filterfunc=lambda whatever: False)
Christian Tismer59202e52013-10-21 03:59:23 +02001186 reportStr = reportSIO.getvalue()
1187 self.assertTrue('SyntaxError' not in reportStr)
1188
Christian Tismer410d9312013-10-22 04:09:28 +02001189 # then check that the filter works on individual files
Larry Hastings7e63b362015-05-08 06:54:58 -07001190 def filter(path):
1191 return not os.path.basename(path).startswith("bad")
Serhiy Storchakac46d1fa2014-01-20 21:59:33 +02001192 with captured_stdout() as reportSIO, self.assertWarns(UserWarning):
Larry Hastings7e63b362015-05-08 06:54:58 -07001193 zipfp.writepy(packagedir, filterfunc=filter)
Christian Tismer410d9312013-10-22 04:09:28 +02001194 reportStr = reportSIO.getvalue()
1195 if reportStr:
1196 print(reportStr)
1197 self.assertTrue('SyntaxError' not in reportStr)
1198
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001199 def test_write_with_optimization(self):
1200 import email
1201 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001202 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001203 optlevel = 1 if __debug__ else 0
Brett Cannonf299abd2015-04-13 14:21:02 -04001204 ext = '.pyc'
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001205
1206 with TemporaryFile() as t, \
Christian Tismer59202e52013-10-21 03:59:23 +02001207 zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001208 zipfp.writepy(packagedir)
1209
1210 names = zipfp.namelist()
1211 self.assertIn('email/__init__' + ext, names)
1212 self.assertIn('email/mime/text' + ext, names)
1213
1214 def test_write_python_directory(self):
1215 os.mkdir(TESTFN2)
1216 try:
1217 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1218 fp.write("print(42)\n")
1219
1220 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1221 fp.write("print(42 * 42)\n")
1222
1223 with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp:
1224 fp.write("bla bla bla\n")
1225
1226 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1227 zipfp.writepy(TESTFN2)
1228
1229 names = zipfp.namelist()
1230 self.assertCompiledIn('mod1.py', names)
1231 self.assertCompiledIn('mod2.py', names)
1232 self.assertNotIn('mod2.txt', names)
1233
1234 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001235 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001236
Christian Tismer410d9312013-10-22 04:09:28 +02001237 def test_write_python_directory_filtered(self):
1238 os.mkdir(TESTFN2)
1239 try:
1240 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1241 fp.write("print(42)\n")
1242
1243 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1244 fp.write("print(42 * 42)\n")
1245
1246 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1247 zipfp.writepy(TESTFN2, filterfunc=lambda fn:
1248 not fn.endswith('mod2.py'))
1249
1250 names = zipfp.namelist()
1251 self.assertCompiledIn('mod1.py', names)
1252 self.assertNotIn('mod2.py', names)
1253
1254 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001255 rmtree(TESTFN2)
Christian Tismer410d9312013-10-22 04:09:28 +02001256
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001257 def test_write_non_pyfile(self):
1258 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1259 with open(TESTFN, 'w') as f:
1260 f.write('most definitely not a python file')
1261 self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
Victor Stinner88b215e2014-09-04 00:51:09 +02001262 unlink(TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001263
1264 def test_write_pyfile_bad_syntax(self):
1265 os.mkdir(TESTFN2)
1266 try:
1267 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1268 fp.write("Bad syntax in python file\n")
1269
1270 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1271 # syntax errors are printed to stdout
1272 with captured_stdout() as s:
1273 zipfp.writepy(os.path.join(TESTFN2, "mod1.py"))
1274
1275 self.assertIn("SyntaxError", s.getvalue())
1276
1277 # as it will not have compiled the python file, it will
Brett Cannonf299abd2015-04-13 14:21:02 -04001278 # include the .py file not .pyc
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001279 names = zipfp.namelist()
1280 self.assertIn('mod1.py', names)
1281 self.assertNotIn('mod1.pyc', names)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001282
1283 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001284 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001285
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001286 def test_write_pathlike(self):
1287 os.mkdir(TESTFN2)
1288 try:
1289 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1290 fp.write("print(42)\n")
1291
1292 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1293 zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py")
1294 names = zipfp.namelist()
1295 self.assertCompiledIn('mod1.py', names)
1296 finally:
1297 rmtree(TESTFN2)
1298
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001299
1300class ExtractTests(unittest.TestCase):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001301
1302 def make_test_file(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001303 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1304 for fpath, fdata in SMALL_TEST_DATA:
1305 zipfp.writestr(fpath, fdata)
Christian Heimes790c8232008-01-07 21:14:23 +00001306
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001307 def test_extract(self):
1308 with temp_cwd():
1309 self.make_test_file()
1310 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1311 for fpath, fdata in SMALL_TEST_DATA:
1312 writtenfile = zipfp.extract(fpath)
1313
1314 # make sure it was written to the right place
1315 correctfile = os.path.join(os.getcwd(), fpath)
1316 correctfile = os.path.normpath(correctfile)
1317
1318 self.assertEqual(writtenfile, correctfile)
1319
1320 # make sure correct data is in correct file
1321 with open(writtenfile, "rb") as f:
1322 self.assertEqual(fdata.encode(), f.read())
1323
1324 unlink(writtenfile)
1325
1326 def _test_extract_with_target(self, target):
1327 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001328 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1329 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001330 writtenfile = zipfp.extract(fpath, target)
Christian Heimes790c8232008-01-07 21:14:23 +00001331
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001332 # make sure it was written to the right place
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001333 correctfile = os.path.join(target, fpath)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001334 correctfile = os.path.normpath(correctfile)
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001335 self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target))
Christian Heimes790c8232008-01-07 21:14:23 +00001336
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001337 # make sure correct data is in correct file
Brian Curtin8fb9b862010-11-18 02:15:28 +00001338 with open(writtenfile, "rb") as f:
1339 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001340
Victor Stinner88b215e2014-09-04 00:51:09 +02001341 unlink(writtenfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001342
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001343 unlink(TESTFN2)
1344
1345 def test_extract_with_target(self):
1346 with temp_dir() as extdir:
1347 self._test_extract_with_target(extdir)
1348
1349 def test_extract_with_target_pathlike(self):
1350 with temp_dir() as extdir:
1351 self._test_extract_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001352
Ezio Melottiafd0d112009-07-15 17:17:17 +00001353 def test_extract_all(self):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001354 with temp_cwd():
1355 self.make_test_file()
1356 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1357 zipfp.extractall()
1358 for fpath, fdata in SMALL_TEST_DATA:
1359 outfile = os.path.join(os.getcwd(), fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001360
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001361 with open(outfile, "rb") as f:
1362 self.assertEqual(fdata.encode(), f.read())
1363
1364 unlink(outfile)
1365
1366 def _test_extract_all_with_target(self, target):
1367 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001368 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001369 zipfp.extractall(target)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001370 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001371 outfile = os.path.join(target, fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001372
Brian Curtin8fb9b862010-11-18 02:15:28 +00001373 with open(outfile, "rb") as f:
1374 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001375
Victor Stinner88b215e2014-09-04 00:51:09 +02001376 unlink(outfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001377
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001378 unlink(TESTFN2)
1379
1380 def test_extract_all_with_target(self):
1381 with temp_dir() as extdir:
1382 self._test_extract_all_with_target(extdir)
1383
1384 def test_extract_all_with_target_pathlike(self):
1385 with temp_dir() as extdir:
1386 self._test_extract_all_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001387
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001388 def check_file(self, filename, content):
1389 self.assertTrue(os.path.isfile(filename))
1390 with open(filename, 'rb') as f:
1391 self.assertEqual(f.read(), content)
1392
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001393 def test_sanitize_windows_name(self):
1394 san = zipfile.ZipFile._sanitize_windows_name
1395 # Passing pathsep in allows this test to work regardless of platform.
1396 self.assertEqual(san(r',,?,C:,foo,bar/z', ','), r'_,C_,foo,bar/z')
1397 self.assertEqual(san(r'a\b,c<d>e|f"g?h*i', ','), r'a\b,c_d_e_f_g_h_i')
1398 self.assertEqual(san('../../foo../../ba..r', '/'), r'foo/ba..r')
1399
1400 def test_extract_hackers_arcnames_common_cases(self):
1401 common_hacknames = [
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001402 ('../foo/bar', 'foo/bar'),
1403 ('foo/../bar', 'foo/bar'),
1404 ('foo/../../bar', 'foo/bar'),
1405 ('foo/bar/..', 'foo/bar'),
1406 ('./../foo/bar', 'foo/bar'),
1407 ('/foo/bar', 'foo/bar'),
1408 ('/foo/../bar', 'foo/bar'),
1409 ('/foo/../../bar', 'foo/bar'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001410 ]
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001411 self._test_extract_hackers_arcnames(common_hacknames)
1412
1413 @unittest.skipIf(os.path.sep != '\\', 'Requires \\ as path separator.')
1414 def test_extract_hackers_arcnames_windows_only(self):
1415 """Test combination of path fixing and windows name sanitization."""
1416 windows_hacknames = [
Christian Tismer59202e52013-10-21 03:59:23 +02001417 (r'..\foo\bar', 'foo/bar'),
1418 (r'..\/foo\/bar', 'foo/bar'),
1419 (r'foo/\..\/bar', 'foo/bar'),
1420 (r'foo\/../\bar', 'foo/bar'),
1421 (r'C:foo/bar', 'foo/bar'),
1422 (r'C:/foo/bar', 'foo/bar'),
1423 (r'C://foo/bar', 'foo/bar'),
1424 (r'C:\foo\bar', 'foo/bar'),
1425 (r'//conky/mountpoint/foo/bar', 'foo/bar'),
1426 (r'\\conky\mountpoint\foo\bar', 'foo/bar'),
1427 (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1428 (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1429 (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1430 (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1431 (r'//?/C:/foo/bar', 'foo/bar'),
1432 (r'\\?\C:\foo\bar', 'foo/bar'),
1433 (r'C:/../C:/foo/bar', 'C_/foo/bar'),
1434 (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
1435 ('../../foo../../ba..r', 'foo/ba..r'),
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001436 ]
1437 self._test_extract_hackers_arcnames(windows_hacknames)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001438
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001439 @unittest.skipIf(os.path.sep != '/', r'Requires / as path separator.')
1440 def test_extract_hackers_arcnames_posix_only(self):
1441 posix_hacknames = [
1442 ('//foo/bar', 'foo/bar'),
1443 ('../../foo../../ba..r', 'foo../ba..r'),
1444 (r'foo/..\bar', r'foo/..\bar'),
1445 ]
1446 self._test_extract_hackers_arcnames(posix_hacknames)
1447
1448 def _test_extract_hackers_arcnames(self, hacknames):
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001449 for arcname, fixedname in hacknames:
1450 content = b'foobar' + arcname.encode()
1451 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001452 zinfo = zipfile.ZipInfo()
1453 # preserve backslashes
1454 zinfo.filename = arcname
1455 zinfo.external_attr = 0o600 << 16
1456 zipfp.writestr(zinfo, content)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001457
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001458 arcname = arcname.replace(os.sep, "/")
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001459 targetpath = os.path.join('target', 'subdir', 'subsub')
1460 correctfile = os.path.join(targetpath, *fixedname.split('/'))
1461
1462 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1463 writtenfile = zipfp.extract(arcname, targetpath)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001464 self.assertEqual(writtenfile, correctfile,
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001465 msg='extract %r: %r != %r' %
1466 (arcname, writtenfile, correctfile))
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001467 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001468 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001469
1470 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1471 zipfp.extractall(targetpath)
1472 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001473 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001474
1475 correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
1476
1477 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1478 writtenfile = zipfp.extract(arcname)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001479 self.assertEqual(writtenfile, correctfile,
1480 msg="extract %r" % arcname)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001481 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001482 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001483
1484 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1485 zipfp.extractall()
1486 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001487 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001488
Victor Stinner88b215e2014-09-04 00:51:09 +02001489 unlink(TESTFN2)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001490
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001491
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001492class OtherTests(unittest.TestCase):
1493 def test_open_via_zip_info(self):
1494 # Create the ZIP archive
1495 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1496 zipfp.writestr("name", "foo")
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001497 with self.assertWarns(UserWarning):
1498 zipfp.writestr("name", "bar")
1499 self.assertEqual(zipfp.namelist(), ["name"] * 2)
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001500
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001501 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1502 infos = zipfp.infolist()
1503 data = b""
1504 for info in infos:
1505 with zipfp.open(info) as zipopen:
1506 data += zipopen.read()
1507 self.assertIn(data, {b"foobar", b"barfoo"})
1508 data = b""
1509 for info in infos:
1510 data += zipfp.read(info)
1511 self.assertIn(data, {b"foobar", b"barfoo"})
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02001512
Gregory P. Smithb0d9ca92009-07-07 05:06:04 +00001513 def test_writestr_extended_local_header_issue1202(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001514 with zipfile.ZipFile(TESTFN2, 'w') as orig_zip:
1515 for data in 'abcdefghijklmnop':
1516 zinfo = zipfile.ZipInfo(data)
1517 zinfo.flag_bits |= 0x08 # Include an extended local header.
1518 orig_zip.writestr(zinfo, data)
1519
1520 def test_close(self):
1521 """Check that the zipfile is closed after the 'with' block."""
1522 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1523 for fpath, fdata in SMALL_TEST_DATA:
1524 zipfp.writestr(fpath, fdata)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001525 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1526 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001527
1528 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001529 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1530 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001531
1532 def test_close_on_exception(self):
1533 """Check that the zipfile is closed if an exception is raised in the
1534 'with' block."""
1535 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1536 for fpath, fdata in SMALL_TEST_DATA:
1537 zipfp.writestr(fpath, fdata)
1538
1539 try:
1540 with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
Georg Brandl4d540882010-10-28 06:42:33 +00001541 raise zipfile.BadZipFile()
1542 except zipfile.BadZipFile:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001543 self.assertIsNone(zipfp2.fp, 'zipfp is not closed')
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00001544
Martin v. Löwisd099b562012-05-01 14:08:22 +02001545 def test_unsupported_version(self):
1546 # File has an extract_version of 120
1547 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 +02001548 b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00xPK\x01\x02x\x03x\x00\x00\x00\x00'
1549 b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
1550 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06'
1551 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 +03001552
Martin v. Löwisd099b562012-05-01 14:08:22 +02001553 self.assertRaises(NotImplementedError, zipfile.ZipFile,
1554 io.BytesIO(data), 'r')
1555
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001556 @requires_zlib
1557 def test_read_unicode_filenames(self):
1558 # bug #10801
1559 fname = findfile('zip_cp437_header.zip')
1560 with zipfile.ZipFile(fname) as zipfp:
1561 for name in zipfp.namelist():
1562 zipfp.open(name).close()
1563
1564 def test_write_unicode_filenames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001565 with zipfile.ZipFile(TESTFN, "w") as zf:
1566 zf.writestr("foo.txt", "Test for unicode filename")
1567 zf.writestr("\xf6.txt", "Test for unicode filename")
Ezio Melottie9615932010-01-24 19:26:24 +00001568 self.assertIsInstance(zf.infolist()[0].filename, str)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001569
1570 with zipfile.ZipFile(TESTFN, "r") as zf:
1571 self.assertEqual(zf.filelist[0].filename, "foo.txt")
1572 self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
Martin v. Löwis8570f6a2008-05-05 17:44:38 +00001573
Serhiy Storchaka764fc9b2015-03-25 10:09:41 +02001574 def test_exclusive_create_zip_file(self):
1575 """Test exclusive creating a new zipfile."""
1576 unlink(TESTFN2)
1577 filename = 'testfile.txt'
1578 content = b'hello, world. this is some content.'
1579 with zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED) as zipfp:
1580 zipfp.writestr(filename, content)
1581 with self.assertRaises(FileExistsError):
1582 zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED)
1583 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1584 self.assertEqual(zipfp.namelist(), [filename])
1585 self.assertEqual(zipfp.read(filename), content)
1586
Ezio Melottiafd0d112009-07-15 17:17:17 +00001587 def test_create_non_existent_file_for_append(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00001588 if os.path.exists(TESTFN):
1589 os.unlink(TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001590
Thomas Wouterscf297e42007-02-23 15:07:44 +00001591 filename = 'testfile.txt'
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001592 content = b'hello, world. this is some content.'
Guido van Rossumd8faa362007-04-27 19:54:29 +00001593
Thomas Wouterscf297e42007-02-23 15:07:44 +00001594 try:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001595 with zipfile.ZipFile(TESTFN, 'a') as zf:
1596 zf.writestr(filename, content)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001597 except OSError:
Thomas Wouterscf297e42007-02-23 15:07:44 +00001598 self.fail('Could not append data to a non-existent zip file.')
1599
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001600 self.assertTrue(os.path.exists(TESTFN))
Thomas Wouterscf297e42007-02-23 15:07:44 +00001601
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001602 with zipfile.ZipFile(TESTFN, 'r') as zf:
1603 self.assertEqual(zf.read(filename), content)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001604
Ezio Melottiafd0d112009-07-15 17:17:17 +00001605 def test_close_erroneous_file(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001606 # This test checks that the ZipFile constructor closes the file object
Ezio Melotti35386712009-12-31 13:22:41 +00001607 # it opens if there's an error in the file. If it doesn't, the
1608 # traceback holds a reference to the ZipFile object and, indirectly,
1609 # the file object.
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001610 # On Windows, this causes the os.unlink() call to fail because the
1611 # underlying file is still open. This is SF bug #412214.
1612 #
Ezio Melotti35386712009-12-31 13:22:41 +00001613 with open(TESTFN, "w") as fp:
1614 fp.write("this is not a legal zip file\n")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001615 try:
1616 zf = zipfile.ZipFile(TESTFN)
Georg Brandl4d540882010-10-28 06:42:33 +00001617 except zipfile.BadZipFile:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001618 pass
1619
Ezio Melottiafd0d112009-07-15 17:17:17 +00001620 def test_is_zip_erroneous_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001621 """Check that is_zipfile() correctly identifies non-zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001622 # - passing a filename
1623 with open(TESTFN, "w") as fp:
1624 fp.write("this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001625 self.assertFalse(zipfile.is_zipfile(TESTFN))
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001626 # - passing a path-like object
1627 self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN)))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001628 # - passing a file object
1629 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001630 self.assertFalse(zipfile.is_zipfile(fp))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001631 # - passing a file-like object
1632 fp = io.BytesIO()
1633 fp.write(b"this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001634 self.assertFalse(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001635 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001636 self.assertFalse(zipfile.is_zipfile(fp))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001637
Serhiy Storchakad2b15272013-01-31 15:27:07 +02001638 def test_damaged_zipfile(self):
1639 """Check that zipfiles with missing bytes at the end raise BadZipFile."""
1640 # - Create a valid zip file
1641 fp = io.BytesIO()
1642 with zipfile.ZipFile(fp, mode="w") as zipf:
1643 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1644 zipfiledata = fp.getvalue()
1645
1646 # - Now create copies of it missing the last N bytes and make sure
1647 # a BadZipFile exception is raised when we try to open it
1648 for N in range(len(zipfiledata)):
1649 fp = io.BytesIO(zipfiledata[:N])
1650 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, fp)
1651
Ezio Melottiafd0d112009-07-15 17:17:17 +00001652 def test_is_zip_valid_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001653 """Check that is_zipfile() correctly identifies zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001654 # - passing a filename
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001655 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1656 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1657
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001658 self.assertTrue(zipfile.is_zipfile(TESTFN))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001659 # - passing a file object
1660 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001661 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001662 fp.seek(0, 0)
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001663 zip_contents = fp.read()
1664 # - passing a file-like object
1665 fp = io.BytesIO()
1666 fp.write(zip_contents)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001667 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001668 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001669 self.assertTrue(zipfile.is_zipfile(fp))
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001670
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001671 def test_non_existent_file_raises_OSError(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001672 # make sure we don't raise an AttributeError when a partially-constructed
1673 # ZipFile instance is finalized; this tests for regression on SF tracker
1674 # bug #403871.
1675
1676 # The bug we're testing for caused an AttributeError to be raised
1677 # when a ZipFile instance was created for a file that did not
1678 # exist; the .fp member was not initialized but was needed by the
1679 # __del__() method. Since the AttributeError is in the __del__(),
1680 # it is ignored, but the user should be sufficiently annoyed by
1681 # the message on the output that regression will be noticed
1682 # quickly.
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001683 self.assertRaises(OSError, zipfile.ZipFile, TESTFN)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001684
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001685 def test_empty_file_raises_BadZipFile(self):
1686 f = open(TESTFN, 'w')
1687 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001688 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001689
Ezio Melotti35386712009-12-31 13:22:41 +00001690 with open(TESTFN, 'w') as fp:
1691 fp.write("short file")
Georg Brandl4d540882010-10-28 06:42:33 +00001692 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001693
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001694 def test_closed_zip_raises_ValueError(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001695 """Verify that testzip() doesn't swallow inappropriate exceptions."""
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001696 data = io.BytesIO()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001697 with zipfile.ZipFile(data, mode="w") as zipf:
1698 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001699
Andrew Svetlov737fb892012-12-18 21:14:22 +02001700 # This is correct; calling .read on a closed ZipFile should raise
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001701 # a ValueError, and so should calling .testzip. An earlier
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001702 # version of .testzip would swallow this exception (and any other)
1703 # and report that the first file in the archive was corrupt.
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001704 self.assertRaises(ValueError, zipf.read, "foo.txt")
1705 self.assertRaises(ValueError, zipf.open, "foo.txt")
1706 self.assertRaises(ValueError, zipf.testzip)
1707 self.assertRaises(ValueError, zipf.writestr, "bogus.txt", "bogus")
Brian Curtin8fb9b862010-11-18 02:15:28 +00001708 with open(TESTFN, 'w') as f:
1709 f.write('zipfile test data')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001710 self.assertRaises(ValueError, zipf.write, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001711
Ezio Melottiafd0d112009-07-15 17:17:17 +00001712 def test_bad_constructor_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001713 """Check that bad modes passed to ZipFile constructor are caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001714 self.assertRaises(ValueError, zipfile.ZipFile, TESTFN, "q")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001715
Ezio Melottiafd0d112009-07-15 17:17:17 +00001716 def test_bad_open_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001717 """Check that bad modes passed to ZipFile.open are caught."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001718 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1719 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1720
1721 with zipfile.ZipFile(TESTFN, mode="r") as zipf:
Serhiy Storchakae670be22016-06-11 19:32:44 +03001722 # read the data to make sure the file is there
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001723 zipf.read("foo.txt")
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001724 self.assertRaises(ValueError, zipf.open, "foo.txt", "q")
Serhiy Storchakae670be22016-06-11 19:32:44 +03001725 # universal newlines support is removed
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001726 self.assertRaises(ValueError, zipf.open, "foo.txt", "U")
1727 self.assertRaises(ValueError, zipf.open, "foo.txt", "rU")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001728
Ezio Melottiafd0d112009-07-15 17:17:17 +00001729 def test_read0(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001730 """Check that calling read(0) on a ZipExtFile object returns an empty
1731 string and doesn't advance file pointer."""
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 # read the data to make sure the file is there
Brian Curtin8fb9b862010-11-18 02:15:28 +00001735 with zipf.open("foo.txt") as f:
1736 for i in range(FIXEDTEST_SIZE):
1737 self.assertEqual(f.read(0), b'')
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001738
Brian Curtin8fb9b862010-11-18 02:15:28 +00001739 self.assertEqual(f.read(), b"O, for a Muse of Fire!")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001740
Ezio Melottiafd0d112009-07-15 17:17:17 +00001741 def test_open_non_existent_item(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001742 """Check that attempting to call open() for an item that doesn't
1743 exist in the archive raises a RuntimeError."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001744 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1745 self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001746
Ezio Melottiafd0d112009-07-15 17:17:17 +00001747 def test_bad_compression_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001748 """Check that bad compression methods passed to ZipFile.open are
1749 caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001750 self.assertRaises(NotImplementedError, zipfile.ZipFile, TESTFN, "w", -1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001751
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001752 def test_unsupported_compression(self):
1753 # data is declared as shrunk, but actually deflated
1754 data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001755 b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
1756 b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
1757 b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1758 b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
1759 b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001760 with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
1761 self.assertRaises(NotImplementedError, zipf.open, 'x')
1762
Ezio Melottiafd0d112009-07-15 17:17:17 +00001763 def test_null_byte_in_filename(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001764 """Check that a filename containing a null byte is properly
1765 terminated."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001766 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1767 zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
1768 self.assertEqual(zipf.namelist(), ['foo.txt'])
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001769
Ezio Melottiafd0d112009-07-15 17:17:17 +00001770 def test_struct_sizes(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001771 """Check that ZIP internal structure sizes are calculated correctly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001772 self.assertEqual(zipfile.sizeEndCentDir, 22)
1773 self.assertEqual(zipfile.sizeCentralDir, 46)
1774 self.assertEqual(zipfile.sizeEndCentDir64, 56)
1775 self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
1776
Ezio Melottiafd0d112009-07-15 17:17:17 +00001777 def test_comments(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001778 """Check that comments on the archive are handled properly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001779
1780 # check default comment is empty
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001781 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1782 self.assertEqual(zipf.comment, b'')
1783 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1784
1785 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1786 self.assertEqual(zipfr.comment, b'')
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001787
1788 # check a simple short comment
1789 comment = b'Bravely taking to his feet, he beat a very brave retreat.'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001790 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1791 zipf.comment = comment
1792 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1793 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1794 self.assertEqual(zipf.comment, comment)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001795
1796 # check a comment of max length
1797 comment2 = ''.join(['%d' % (i**3 % 10) for i in range((1 << 16)-1)])
1798 comment2 = comment2.encode("ascii")
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001799 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1800 zipf.comment = comment2
1801 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1802
1803 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1804 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001805
1806 # check a comment that is too long is truncated
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001807 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001808 with self.assertWarns(UserWarning):
1809 zipf.comment = comment2 + b'oops'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001810 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1811 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1812 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001813
Antoine Pitrouc3991852012-06-30 17:31:37 +02001814 # check that comments are correctly modified in append mode
1815 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1816 zipf.comment = b"original comment"
1817 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1818 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1819 zipf.comment = b"an updated comment"
1820 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1821 self.assertEqual(zipf.comment, b"an updated comment")
1822
1823 # check that comments are correctly shortened in append mode
1824 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1825 zipf.comment = b"original comment that's longer"
1826 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1827 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1828 zipf.comment = b"shorter comment"
1829 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1830 self.assertEqual(zipf.comment, b"shorter comment")
1831
R David Murrayf50b38a2012-04-12 18:44:58 -04001832 def test_unicode_comment(self):
1833 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1834 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1835 with self.assertRaises(TypeError):
1836 zipf.comment = "this is an error"
1837
1838 def test_change_comment_in_empty_archive(self):
1839 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1840 self.assertFalse(zipf.filelist)
1841 zipf.comment = b"this is a comment"
1842 with zipfile.ZipFile(TESTFN, "r") as zipf:
1843 self.assertEqual(zipf.comment, b"this is a comment")
1844
1845 def test_change_comment_in_nonempty_archive(self):
1846 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1847 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1848 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1849 self.assertTrue(zipf.filelist)
1850 zipf.comment = b"this is a comment"
1851 with zipfile.ZipFile(TESTFN, "r") as zipf:
1852 self.assertEqual(zipf.comment, b"this is a comment")
1853
Georg Brandl268e4d42010-10-14 06:59:45 +00001854 def test_empty_zipfile(self):
1855 # Check that creating a file in 'w' or 'a' mode and closing without
1856 # adding any files to the archives creates a valid empty ZIP file
1857 zipf = zipfile.ZipFile(TESTFN, mode="w")
1858 zipf.close()
1859 try:
1860 zipf = zipfile.ZipFile(TESTFN, mode="r")
1861 except zipfile.BadZipFile:
1862 self.fail("Unable to create empty ZIP file in 'w' mode")
1863
1864 zipf = zipfile.ZipFile(TESTFN, mode="a")
1865 zipf.close()
1866 try:
1867 zipf = zipfile.ZipFile(TESTFN, mode="r")
1868 except:
1869 self.fail("Unable to create empty ZIP file in 'a' mode")
1870
1871 def test_open_empty_file(self):
1872 # Issue 1710703: Check that opening a file with less than 22 bytes
Georg Brandl4d540882010-10-28 06:42:33 +00001873 # raises a BadZipFile exception (rather than the previously unhelpful
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001874 # OSError)
Georg Brandl268e4d42010-10-14 06:59:45 +00001875 f = open(TESTFN, 'w')
1876 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001877 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN, 'r')
Georg Brandl268e4d42010-10-14 06:59:45 +00001878
Senthil Kumaran29fa9d42011-10-20 01:46:00 +08001879 def test_create_zipinfo_before_1980(self):
1880 self.assertRaises(ValueError,
1881 zipfile.ZipInfo, 'seventies', (1979, 1, 1, 0, 0, 0))
1882
Mickaël Schoentgen992347d2019-09-09 15:08:54 +02001883 def test_create_empty_zipinfo_repr(self):
1884 """Before bpo-26185, repr() on empty ZipInfo object was failing."""
1885 zi = zipfile.ZipInfo(filename="empty")
1886 self.assertEqual(repr(zi), "<ZipInfo filename='empty' file_size=0>")
1887
1888 def test_create_empty_zipinfo_default_attributes(self):
1889 """Ensure all required attributes are set."""
1890 zi = zipfile.ZipInfo()
1891 self.assertEqual(zi.orig_filename, "NoName")
1892 self.assertEqual(zi.filename, "NoName")
1893 self.assertEqual(zi.date_time, (1980, 1, 1, 0, 0, 0))
1894 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
1895 self.assertEqual(zi.comment, b"")
1896 self.assertEqual(zi.extra, b"")
1897 self.assertIn(zi.create_system, (0, 3))
1898 self.assertEqual(zi.create_version, zipfile.DEFAULT_VERSION)
1899 self.assertEqual(zi.extract_version, zipfile.DEFAULT_VERSION)
1900 self.assertEqual(zi.reserved, 0)
1901 self.assertEqual(zi.flag_bits, 0)
1902 self.assertEqual(zi.volume, 0)
1903 self.assertEqual(zi.internal_attr, 0)
1904 self.assertEqual(zi.external_attr, 0)
1905
1906 # Before bpo-26185, both were missing
1907 self.assertEqual(zi.file_size, 0)
1908 self.assertEqual(zi.compress_size, 0)
1909
Gregory P. Smith0af8a862014-05-29 23:42:14 -07001910 def test_zipfile_with_short_extra_field(self):
1911 """If an extra field in the header is less than 4 bytes, skip it."""
1912 zipdata = (
1913 b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1914 b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1915 b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1916 b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1917 b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1918 b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1919 b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1920 )
1921 with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1922 # testzip returns the name of the first corrupt file, or None
1923 self.assertIsNone(zipf.testzip())
1924
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001925 def test_open_conflicting_handles(self):
1926 # It's only possible to open one writable file handle at a time
1927 msg1 = b"It's fun to charter an accountant!"
1928 msg2 = b"And sail the wide accountant sea"
1929 msg3 = b"To find, explore the funds offshore"
1930 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
1931 with zipf.open('foo', mode='w') as w2:
1932 w2.write(msg1)
1933 with zipf.open('bar', mode='w') as w1:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001934 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001935 zipf.open('handle', mode='w')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001936 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001937 zipf.open('foo', mode='r')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001938 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001939 zipf.writestr('str', 'abcde')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001940 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001941 zipf.write(__file__, 'file')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001942 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001943 zipf.close()
1944 w1.write(msg2)
1945 with zipf.open('baz', mode='w') as w2:
1946 w2.write(msg3)
1947
1948 with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1949 self.assertEqual(zipf.read('foo'), msg1)
1950 self.assertEqual(zipf.read('bar'), msg2)
1951 self.assertEqual(zipf.read('baz'), msg3)
1952 self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
1953
John Jolly066df4f2018-01-30 01:51:35 -07001954 def test_seek_tell(self):
1955 # Test seek functionality
1956 txt = b"Where's Bruce?"
1957 bloc = txt.find(b"Bruce")
1958 # Check seek on a file
1959 with zipfile.ZipFile(TESTFN, "w") as zipf:
1960 zipf.writestr("foo.txt", txt)
1961 with zipfile.ZipFile(TESTFN, "r") as zipf:
1962 with zipf.open("foo.txt", "r") as fp:
1963 fp.seek(bloc, os.SEEK_SET)
1964 self.assertEqual(fp.tell(), bloc)
1965 fp.seek(-bloc, os.SEEK_CUR)
1966 self.assertEqual(fp.tell(), 0)
1967 fp.seek(bloc, os.SEEK_CUR)
1968 self.assertEqual(fp.tell(), bloc)
1969 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1970 fp.seek(0, os.SEEK_END)
1971 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001972 fp.seek(0, os.SEEK_SET)
1973 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07001974 # Check seek on memory file
1975 data = io.BytesIO()
1976 with zipfile.ZipFile(data, mode="w") as zipf:
1977 zipf.writestr("foo.txt", txt)
1978 with zipfile.ZipFile(data, mode="r") as zipf:
1979 with zipf.open("foo.txt", "r") as fp:
1980 fp.seek(bloc, os.SEEK_SET)
1981 self.assertEqual(fp.tell(), bloc)
1982 fp.seek(-bloc, os.SEEK_CUR)
1983 self.assertEqual(fp.tell(), 0)
1984 fp.seek(bloc, os.SEEK_CUR)
1985 self.assertEqual(fp.tell(), bloc)
1986 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1987 fp.seek(0, os.SEEK_END)
1988 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001989 fp.seek(0, os.SEEK_SET)
1990 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07001991
Berker Peksag2f1b8572019-09-12 17:13:44 +03001992 @requires_bz2
1993 def test_decompress_without_3rd_party_library(self):
1994 data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1995 zip_file = io.BytesIO(data)
1996 with zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_BZIP2) as zf:
1997 zf.writestr('a.txt', b'a')
1998 with mock.patch('zipfile.bz2', None):
1999 with zipfile.ZipFile(zip_file) as zf:
2000 self.assertRaises(RuntimeError, zf.extract, 'a.txt')
2001
Guido van Rossumd8faa362007-04-27 19:54:29 +00002002 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002003 unlink(TESTFN)
2004 unlink(TESTFN2)
2005
Thomas Wouterscf297e42007-02-23 15:07:44 +00002006
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002007class AbstractBadCrcTests:
2008 def test_testzip_with_bad_crc(self):
2009 """Tests that files with bad CRCs return their name from testzip."""
2010 zipdata = self.zip_with_bad_crc
2011
2012 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2013 # testzip returns the name of the first corrupt file, or None
2014 self.assertEqual('afile', zipf.testzip())
2015
2016 def test_read_with_bad_crc(self):
2017 """Tests that files with bad CRCs raise a BadZipFile exception when read."""
2018 zipdata = self.zip_with_bad_crc
2019
2020 # Using ZipFile.read()
2021 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2022 self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile')
2023
2024 # Using ZipExtFile.read()
2025 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2026 with zipf.open('afile', 'r') as corrupt_file:
2027 self.assertRaises(zipfile.BadZipFile, corrupt_file.read)
2028
2029 # Same with small reads (in order to exercise the buffering logic)
2030 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2031 with zipf.open('afile', 'r') as corrupt_file:
2032 corrupt_file.MIN_READ_SIZE = 2
2033 with self.assertRaises(zipfile.BadZipFile):
2034 while corrupt_file.read(2):
2035 pass
2036
2037
2038class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2039 compression = zipfile.ZIP_STORED
2040 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002041 b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
2042 b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
2043 b'ilehello,AworldP'
2044 b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
2045 b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
2046 b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
2047 b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
2048 b'\0\0/\0\0\0\0\0')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002049
2050@requires_zlib
2051class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2052 compression = zipfile.ZIP_DEFLATED
2053 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002054 b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
2055 b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2056 b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
2057 b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
2058 b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
2059 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
2060 b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
2061 b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002062
2063@requires_bz2
2064class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2065 compression = zipfile.ZIP_BZIP2
2066 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002067 b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA'
2068 b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2069 b'ileBZh91AY&SY\xd4\xa8\xca'
2070 b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5'
2071 b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f'
2072 b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14'
2073 b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8'
2074 b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'
2075 b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK'
2076 b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00'
2077 b'\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002078
2079@requires_lzma
2080class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2081 compression = zipfile.ZIP_LZMA
2082 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002083 b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2084 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2085 b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I'
2086 b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK'
2087 b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2088 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00'
2089 b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil'
2090 b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
2091 b'\x00>\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002092
2093
Thomas Wouterscf297e42007-02-23 15:07:44 +00002094class DecryptionTests(unittest.TestCase):
Ezio Melotti35386712009-12-31 13:22:41 +00002095 """Check that ZIP decryption works. Since the library does not
2096 support encryption at the moment, we use a pre-generated encrypted
2097 ZIP file."""
Thomas Wouterscf297e42007-02-23 15:07:44 +00002098
2099 data = (
Christian Tismer59202e52013-10-21 03:59:23 +02002100 b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
2101 b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
2102 b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
2103 b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
2104 b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
2105 b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
2106 b'\x00\x00L\x00\x00\x00\x00\x00' )
Christian Heimesfdab48e2008-01-20 09:06:41 +00002107 data2 = (
Christian Tismer59202e52013-10-21 03:59:23 +02002108 b'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
2109 b'\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
2110 b'\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
2111 b'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
2112 b'\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
2113 b'\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
2114 b'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
2115 b'\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
Thomas Wouterscf297e42007-02-23 15:07:44 +00002116
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002117 plain = b'zipfile.py encryption test'
Christian Heimesfdab48e2008-01-20 09:06:41 +00002118 plain2 = b'\x00'*512
Thomas Wouterscf297e42007-02-23 15:07:44 +00002119
2120 def setUp(self):
Ezio Melotti35386712009-12-31 13:22:41 +00002121 with open(TESTFN, "wb") as fp:
2122 fp.write(self.data)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002123 self.zip = zipfile.ZipFile(TESTFN, "r")
Ezio Melotti35386712009-12-31 13:22:41 +00002124 with open(TESTFN2, "wb") as fp:
2125 fp.write(self.data2)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002126 self.zip2 = zipfile.ZipFile(TESTFN2, "r")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002127
2128 def tearDown(self):
2129 self.zip.close()
2130 os.unlink(TESTFN)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002131 self.zip2.close()
2132 os.unlink(TESTFN2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002133
Ezio Melottiafd0d112009-07-15 17:17:17 +00002134 def test_no_password(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00002135 # Reading the encrypted file without password
2136 # must generate a RunTime exception
2137 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002138 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002139
Ezio Melottiafd0d112009-07-15 17:17:17 +00002140 def test_bad_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002141 self.zip.setpassword(b"perl")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002142 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002143 self.zip2.setpassword(b"perl")
2144 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Guido van Rossumd8faa362007-04-27 19:54:29 +00002145
Ezio Melotti975077a2011-05-19 22:03:22 +03002146 @requires_zlib
Ezio Melottiafd0d112009-07-15 17:17:17 +00002147 def test_good_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002148 self.zip.setpassword(b"python")
Ezio Melotti35386712009-12-31 13:22:41 +00002149 self.assertEqual(self.zip.read("test.txt"), self.plain)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002150 self.zip2.setpassword(b"12345")
Ezio Melotti35386712009-12-31 13:22:41 +00002151 self.assertEqual(self.zip2.read("zero"), self.plain2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002152
R. David Murray8d855d82010-12-21 21:53:37 +00002153 def test_unicode_password(self):
2154 self.assertRaises(TypeError, self.zip.setpassword, "unicode")
2155 self.assertRaises(TypeError, self.zip.read, "test.txt", "python")
2156 self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python")
2157 self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python")
2158
Serhiy Storchaka5c32af72019-10-27 10:22:14 +02002159 def test_seek_tell(self):
2160 self.zip.setpassword(b"python")
2161 txt = self.plain
2162 test_word = b'encryption'
2163 bloc = txt.find(test_word)
2164 bloc_len = len(test_word)
2165 with self.zip.open("test.txt", "r") as fp:
2166 fp.seek(bloc, os.SEEK_SET)
2167 self.assertEqual(fp.tell(), bloc)
2168 fp.seek(-bloc, os.SEEK_CUR)
2169 self.assertEqual(fp.tell(), 0)
2170 fp.seek(bloc, os.SEEK_CUR)
2171 self.assertEqual(fp.tell(), bloc)
2172 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2173
2174 # Make sure that the second read after seeking back beyond
2175 # _readbuffer returns the same content (ie. rewind to the start of
2176 # the file to read forward to the required position).
2177 old_read_size = fp.MIN_READ_SIZE
2178 fp.MIN_READ_SIZE = 1
2179 fp._readbuffer = b''
2180 fp._offset = 0
2181 fp.seek(0, os.SEEK_SET)
2182 self.assertEqual(fp.tell(), 0)
2183 fp.seek(bloc, os.SEEK_CUR)
2184 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2185 fp.MIN_READ_SIZE = old_read_size
2186
2187 fp.seek(0, os.SEEK_END)
2188 self.assertEqual(fp.tell(), len(txt))
2189 fp.seek(0, os.SEEK_SET)
2190 self.assertEqual(fp.tell(), 0)
2191
2192 # Read the file completely to definitely call any eof integrity
2193 # checks (crc) and make sure they still pass.
2194 fp.read()
2195
2196
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002197class AbstractTestsWithRandomBinaryFiles:
2198 @classmethod
2199 def setUpClass(cls):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002200 datacount = randint(16, 64)*1024 + randint(1, 1024)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002201 cls.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
2202 for i in range(datacount))
Guido van Rossumd8faa362007-04-27 19:54:29 +00002203
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002204 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002205 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +00002206 with open(TESTFN, "wb") as fp:
2207 fp.write(self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002208
2209 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002210 unlink(TESTFN)
2211 unlink(TESTFN2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002212
Ezio Melottiafd0d112009-07-15 17:17:17 +00002213 def make_test_archive(self, f, compression):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002214 # Create the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002215 with zipfile.ZipFile(f, "w", compression) as zipfp:
2216 zipfp.write(TESTFN, "another.name")
2217 zipfp.write(TESTFN, TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002218
Ezio Melottiafd0d112009-07-15 17:17:17 +00002219 def zip_test(self, f, compression):
2220 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002221
2222 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002223 with zipfile.ZipFile(f, "r", compression) as zipfp:
2224 testdata = zipfp.read(TESTFN)
2225 self.assertEqual(len(testdata), len(self.data))
2226 self.assertEqual(testdata, self.data)
2227 self.assertEqual(zipfp.read("another.name"), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002228
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002229 def test_read(self):
2230 for f in get_files(self):
2231 self.zip_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002232
Ezio Melottiafd0d112009-07-15 17:17:17 +00002233 def zip_open_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 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002239 with zipfp.open(TESTFN) as zipopen1:
2240 while True:
2241 read_data = zipopen1.read(256)
2242 if not read_data:
2243 break
2244 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002245
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002246 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002247 with zipfp.open("another.name") as zipopen2:
2248 while True:
2249 read_data = zipopen2.read(256)
2250 if not read_data:
2251 break
2252 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002253
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002254 testdata1 = b''.join(zipdata1)
2255 self.assertEqual(len(testdata1), len(self.data))
2256 self.assertEqual(testdata1, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002257
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002258 testdata2 = b''.join(zipdata2)
Ezio Melotti35386712009-12-31 13:22:41 +00002259 self.assertEqual(len(testdata2), len(self.data))
2260 self.assertEqual(testdata2, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002261
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002262 def test_open(self):
2263 for f in get_files(self):
2264 self.zip_open_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002265
Ezio Melottiafd0d112009-07-15 17:17:17 +00002266 def zip_random_open_test(self, f, compression):
2267 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002268
2269 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002270 with zipfile.ZipFile(f, "r", compression) as zipfp:
2271 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002272 with zipfp.open(TESTFN) as zipopen1:
2273 while True:
2274 read_data = zipopen1.read(randint(1, 1024))
2275 if not read_data:
2276 break
2277 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002278
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002279 testdata = b''.join(zipdata1)
2280 self.assertEqual(len(testdata), len(self.data))
2281 self.assertEqual(testdata, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002282
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002283 def test_random_open(self):
2284 for f in get_files(self):
2285 self.zip_random_open_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002286
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00002287
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002288class StoredTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2289 unittest.TestCase):
2290 compression = zipfile.ZIP_STORED
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02002291
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002292@requires_zlib
2293class DeflateTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2294 unittest.TestCase):
2295 compression = zipfile.ZIP_DEFLATED
2296
2297@requires_bz2
2298class Bzip2TestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2299 unittest.TestCase):
2300 compression = zipfile.ZIP_BZIP2
2301
2302@requires_lzma
2303class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2304 unittest.TestCase):
2305 compression = zipfile.ZIP_LZMA
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002306
Ezio Melotti76430242009-07-11 18:28:48 +00002307
luzpaza5293b42017-11-05 07:37:50 -06002308# Provide the tell() method but not seek()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002309class Tellable:
2310 def __init__(self, fp):
2311 self.fp = fp
2312 self.offset = 0
2313
2314 def write(self, data):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002315 n = self.fp.write(data)
2316 self.offset += n
2317 return n
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002318
2319 def tell(self):
2320 return self.offset
2321
2322 def flush(self):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002323 self.fp.flush()
2324
2325class Unseekable:
2326 def __init__(self, fp):
2327 self.fp = fp
2328
2329 def write(self, data):
2330 return self.fp.write(data)
2331
2332 def flush(self):
2333 self.fp.flush()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002334
2335class UnseekableTests(unittest.TestCase):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002336 def test_writestr(self):
2337 for wrapper in (lambda f: f), Tellable, Unseekable:
2338 with self.subTest(wrapper=wrapper):
2339 f = io.BytesIO()
2340 f.write(b'abc')
2341 bf = io.BufferedWriter(f)
2342 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2343 zipfp.writestr('ones', b'111')
2344 zipfp.writestr('twos', b'222')
2345 self.assertEqual(f.getvalue()[:5], b'abcPK')
2346 with zipfile.ZipFile(f, mode='r') as zipf:
2347 with zipf.open('ones') as zopen:
2348 self.assertEqual(zopen.read(), b'111')
2349 with zipf.open('twos') as zopen:
2350 self.assertEqual(zopen.read(), b'222')
2351
2352 def test_write(self):
2353 for wrapper in (lambda f: f), Tellable, Unseekable:
2354 with self.subTest(wrapper=wrapper):
2355 f = io.BytesIO()
2356 f.write(b'abc')
2357 bf = io.BufferedWriter(f)
2358 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2359 self.addCleanup(unlink, TESTFN)
2360 with open(TESTFN, 'wb') as f2:
2361 f2.write(b'111')
2362 zipfp.write(TESTFN, 'ones')
2363 with open(TESTFN, 'wb') as f2:
2364 f2.write(b'222')
2365 zipfp.write(TESTFN, 'twos')
2366 self.assertEqual(f.getvalue()[:5], b'abcPK')
2367 with zipfile.ZipFile(f, mode='r') as zipf:
2368 with zipf.open('ones') as zopen:
2369 self.assertEqual(zopen.read(), b'111')
2370 with zipf.open('twos') as zopen:
2371 self.assertEqual(zopen.read(), b'222')
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002372
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002373 def test_open_write(self):
2374 for wrapper in (lambda f: f), Tellable, Unseekable:
2375 with self.subTest(wrapper=wrapper):
2376 f = io.BytesIO()
2377 f.write(b'abc')
2378 bf = io.BufferedWriter(f)
2379 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
2380 with zipf.open('ones', 'w') as zopen:
2381 zopen.write(b'111')
2382 with zipf.open('twos', 'w') as zopen:
2383 zopen.write(b'222')
2384 self.assertEqual(f.getvalue()[:5], b'abcPK')
2385 with zipfile.ZipFile(f) as zipf:
2386 self.assertEqual(zipf.read('ones'), b'111')
2387 self.assertEqual(zipf.read('twos'), b'222')
2388
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002389
Ezio Melotti975077a2011-05-19 22:03:22 +03002390@requires_zlib
Guido van Rossumd8faa362007-04-27 19:54:29 +00002391class TestsWithMultipleOpens(unittest.TestCase):
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002392 @classmethod
2393 def setUpClass(cls):
2394 cls.data1 = b'111' + getrandbytes(10000)
2395 cls.data2 = b'222' + getrandbytes(10000)
2396
2397 def make_test_archive(self, f):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002398 # Create the ZIP archive
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002399 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
2400 zipfp.writestr('ones', self.data1)
2401 zipfp.writestr('twos', self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002402
Ezio Melottiafd0d112009-07-15 17:17:17 +00002403 def test_same_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002404 # Verify that (when the ZipFile is in control of creating file objects)
2405 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002406 for f in get_files(self):
2407 self.make_test_archive(f)
2408 with zipfile.ZipFile(f, mode="r") as zipf:
2409 with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
2410 data1 = zopen1.read(500)
2411 data2 = zopen2.read(500)
2412 data1 += zopen1.read()
2413 data2 += zopen2.read()
2414 self.assertEqual(data1, data2)
2415 self.assertEqual(data1, self.data1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002416
Ezio Melottiafd0d112009-07-15 17:17:17 +00002417 def test_different_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('twos') as zopen2:
2424 data1 = zopen1.read(500)
2425 data2 = zopen2.read(500)
2426 data1 += zopen1.read()
2427 data2 += zopen2.read()
2428 self.assertEqual(data1, self.data1)
2429 self.assertEqual(data2, self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002430
Ezio Melottiafd0d112009-07-15 17:17:17 +00002431 def test_interleaved(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:
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002437 with zipf.open('ones') as zopen1:
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002438 data1 = zopen1.read(500)
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002439 with zipf.open('twos') as zopen2:
2440 data2 = zopen2.read(500)
2441 data1 += zopen1.read()
2442 data2 += zopen2.read()
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002443 self.assertEqual(data1, self.data1)
2444 self.assertEqual(data2, self.data2)
2445
2446 def test_read_after_close(self):
2447 for f in get_files(self):
2448 self.make_test_archive(f)
2449 with contextlib.ExitStack() as stack:
2450 with zipfile.ZipFile(f, 'r') as zipf:
2451 zopen1 = stack.enter_context(zipf.open('ones'))
2452 zopen2 = stack.enter_context(zipf.open('twos'))
Brian Curtin8fb9b862010-11-18 02:15:28 +00002453 data1 = zopen1.read(500)
2454 data2 = zopen2.read(500)
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002455 data1 += zopen1.read()
2456 data2 += zopen2.read()
2457 self.assertEqual(data1, self.data1)
2458 self.assertEqual(data2, self.data2)
2459
2460 def test_read_after_write(self):
2461 for f in get_files(self):
2462 with zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as zipf:
2463 zipf.writestr('ones', self.data1)
2464 zipf.writestr('twos', self.data2)
2465 with zipf.open('ones') as zopen1:
2466 data1 = zopen1.read(500)
2467 self.assertEqual(data1, self.data1[:500])
2468 with zipfile.ZipFile(f, 'r') as zipf:
2469 data1 = zipf.read('ones')
2470 data2 = zipf.read('twos')
2471 self.assertEqual(data1, self.data1)
2472 self.assertEqual(data2, self.data2)
2473
2474 def test_write_after_read(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 with zipf.open('ones') as zopen1:
2479 zopen1.read(500)
2480 zipf.writestr('twos', self.data2)
2481 with zipfile.ZipFile(f, 'r') as zipf:
2482 data1 = zipf.read('ones')
2483 data2 = zipf.read('twos')
2484 self.assertEqual(data1, self.data1)
2485 self.assertEqual(data2, self.data2)
2486
2487 def test_many_opens(self):
2488 # Verify that read() and open() promptly close the file descriptor,
2489 # and don't rely on the garbage collector to free resources.
2490 self.make_test_archive(TESTFN2)
2491 with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
2492 for x in range(100):
2493 zipf.read('ones')
2494 with zipf.open('ones') as zopen1:
2495 pass
2496 with open(os.devnull) as f:
2497 self.assertLess(f.fileno(), 100)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002498
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002499 def test_write_while_reading(self):
2500 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
2501 zipf.writestr('ones', self.data1)
2502 with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
2503 with zipf.open('ones', 'r') as r1:
2504 data1 = r1.read(500)
2505 with zipf.open('twos', 'w') as w1:
2506 w1.write(self.data2)
2507 data1 += r1.read()
2508 self.assertEqual(data1, self.data1)
2509 with zipfile.ZipFile(TESTFN2) as zipf:
2510 self.assertEqual(zipf.read('twos'), self.data2)
2511
Guido van Rossumd8faa362007-04-27 19:54:29 +00002512 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002513 unlink(TESTFN2)
2514
Guido van Rossumd8faa362007-04-27 19:54:29 +00002515
Martin v. Löwis59e47792009-01-24 14:10:07 +00002516class TestWithDirectory(unittest.TestCase):
2517 def setUp(self):
2518 os.mkdir(TESTFN2)
2519
Ezio Melottiafd0d112009-07-15 17:17:17 +00002520 def test_extract_dir(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002521 with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
2522 zipf.extractall(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002523 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
2524 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
2525 self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
2526
Ezio Melottiafd0d112009-07-15 17:17:17 +00002527 def test_bug_6050(self):
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002528 # Extraction should succeed if directories already exist
2529 os.mkdir(os.path.join(TESTFN2, "a"))
Ezio Melottiafd0d112009-07-15 17:17:17 +00002530 self.test_extract_dir()
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002531
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002532 def test_write_dir(self):
2533 dirpath = os.path.join(TESTFN2, "x")
2534 os.mkdir(dirpath)
2535 mode = os.stat(dirpath).st_mode & 0xFFFF
2536 with zipfile.ZipFile(TESTFN, "w") as zipf:
2537 zipf.write(dirpath)
2538 zinfo = zipf.filelist[0]
2539 self.assertTrue(zinfo.filename.endswith("/x/"))
2540 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2541 zipf.write(dirpath, "y")
2542 zinfo = zipf.filelist[1]
2543 self.assertTrue(zinfo.filename, "y/")
2544 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2545 with zipfile.ZipFile(TESTFN, "r") as zipf:
2546 zinfo = zipf.filelist[0]
2547 self.assertTrue(zinfo.filename.endswith("/x/"))
2548 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2549 zinfo = zipf.filelist[1]
2550 self.assertTrue(zinfo.filename, "y/")
2551 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2552 target = os.path.join(TESTFN2, "target")
2553 os.mkdir(target)
2554 zipf.extractall(target)
2555 self.assertTrue(os.path.isdir(os.path.join(target, "y")))
2556 self.assertEqual(len(os.listdir(target)), 2)
2557
2558 def test_writestr_dir(self):
Martin v. Löwis59e47792009-01-24 14:10:07 +00002559 os.mkdir(os.path.join(TESTFN2, "x"))
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002560 with zipfile.ZipFile(TESTFN, "w") as zipf:
2561 zipf.writestr("x/", b'')
2562 zinfo = zipf.filelist[0]
2563 self.assertEqual(zinfo.filename, "x/")
2564 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2565 with zipfile.ZipFile(TESTFN, "r") as zipf:
2566 zinfo = zipf.filelist[0]
2567 self.assertTrue(zinfo.filename.endswith("x/"))
2568 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2569 target = os.path.join(TESTFN2, "target")
2570 os.mkdir(target)
2571 zipf.extractall(target)
2572 self.assertTrue(os.path.isdir(os.path.join(target, "x")))
2573 self.assertEqual(os.listdir(target), ["x"])
Martin v. Löwis59e47792009-01-24 14:10:07 +00002574
2575 def tearDown(self):
Victor Stinner57004c62014-09-04 00:49:01 +02002576 rmtree(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002577 if os.path.exists(TESTFN):
Ezio Melotti76430242009-07-11 18:28:48 +00002578 unlink(TESTFN)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002579
Guido van Rossumd8faa362007-04-27 19:54:29 +00002580
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002581class ZipInfoTests(unittest.TestCase):
2582 def test_from_file(self):
2583 zi = zipfile.ZipInfo.from_file(__file__)
2584 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2585 self.assertFalse(zi.is_dir())
Serhiy Storchaka8606e952017-03-08 14:37:51 +02002586 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2587
2588 def test_from_file_pathlike(self):
2589 zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
2590 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2591 self.assertFalse(zi.is_dir())
2592 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2593
2594 def test_from_file_bytes(self):
2595 zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
2596 self.assertEqual(posixpath.basename(zi.filename), 'test')
2597 self.assertFalse(zi.is_dir())
2598 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2599
2600 def test_from_file_fileno(self):
2601 with open(__file__, 'rb') as f:
2602 zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
2603 self.assertEqual(posixpath.basename(zi.filename), 'test')
2604 self.assertFalse(zi.is_dir())
2605 self.assertEqual(zi.file_size, os.path.getsize(__file__))
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002606
2607 def test_from_dir(self):
2608 dirpath = os.path.dirname(os.path.abspath(__file__))
2609 zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
2610 self.assertEqual(zi.filename, 'stdlib_tests/')
2611 self.assertTrue(zi.is_dir())
2612 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
2613 self.assertEqual(zi.file_size, 0)
2614
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002615
2616class CommandLineTest(unittest.TestCase):
2617
2618 def zipfilecmd(self, *args, **kwargs):
2619 rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args,
2620 **kwargs)
2621 return out.replace(os.linesep.encode(), b'\n')
2622
2623 def zipfilecmd_failure(self, *args):
2624 return script_helper.assert_python_failure('-m', 'zipfile', *args)
2625
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002626 def test_bad_use(self):
2627 rc, out, err = self.zipfilecmd_failure()
2628 self.assertEqual(out, b'')
2629 self.assertIn(b'usage', err.lower())
2630 self.assertIn(b'error', err.lower())
2631 self.assertIn(b'required', err.lower())
2632 rc, out, err = self.zipfilecmd_failure('-l', '')
2633 self.assertEqual(out, b'')
2634 self.assertNotEqual(err.strip(), b'')
2635
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002636 def test_test_command(self):
2637 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002638 for opt in '-t', '--test':
2639 out = self.zipfilecmd(opt, zip_name)
2640 self.assertEqual(out.rstrip(), b'Done testing')
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002641 zip_name = findfile('testtar.tar')
2642 rc, out, err = self.zipfilecmd_failure('-t', zip_name)
2643 self.assertEqual(out, b'')
2644
2645 def test_list_command(self):
2646 zip_name = findfile('zipdir.zip')
2647 t = io.StringIO()
2648 with zipfile.ZipFile(zip_name, 'r') as tf:
2649 tf.printdir(t)
2650 expected = t.getvalue().encode('ascii', 'backslashreplace')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002651 for opt in '-l', '--list':
2652 out = self.zipfilecmd(opt, zip_name,
2653 PYTHONIOENCODING='ascii:backslashreplace')
2654 self.assertEqual(out, expected)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002655
Serhiy Storchakab4293ef2016-10-23 22:32:30 +03002656 @requires_zlib
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002657 def test_create_command(self):
2658 self.addCleanup(unlink, TESTFN)
2659 with open(TESTFN, 'w') as f:
2660 f.write('test 1')
2661 os.mkdir(TESTFNDIR)
2662 self.addCleanup(rmtree, TESTFNDIR)
2663 with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f:
2664 f.write('test 2')
2665 files = [TESTFN, TESTFNDIR]
2666 namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt']
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002667 for opt in '-c', '--create':
2668 try:
2669 out = self.zipfilecmd(opt, TESTFN2, *files)
2670 self.assertEqual(out, b'')
2671 with zipfile.ZipFile(TESTFN2) as zf:
2672 self.assertEqual(zf.namelist(), namelist)
2673 self.assertEqual(zf.read(namelist[0]), b'test 1')
2674 self.assertEqual(zf.read(namelist[2]), b'test 2')
2675 finally:
2676 unlink(TESTFN2)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002677
2678 def test_extract_command(self):
2679 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002680 for opt in '-e', '--extract':
2681 with temp_dir() as extdir:
2682 out = self.zipfilecmd(opt, zip_name, extdir)
2683 self.assertEqual(out, b'')
2684 with zipfile.ZipFile(zip_name) as zf:
2685 for zi in zf.infolist():
2686 path = os.path.join(extdir,
2687 zi.filename.replace('/', os.sep))
2688 if zi.is_dir():
2689 self.assertTrue(os.path.isdir(path))
2690 else:
2691 self.assertTrue(os.path.isfile(path))
2692 with open(path, 'rb') as f:
2693 self.assertEqual(f.read(), zf.read(zi))
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002694
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002695
2696# Poor man's technique to consume a (smallish) iterable.
2697consume = tuple
2698
2699
shireenraoa4e29912019-08-24 11:26:41 -04002700def add_dirs(zf):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002701 """
shireenraoa4e29912019-08-24 11:26:41 -04002702 Given a writable zip file zf, inject directory entries for
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002703 any directories implied by the presence of children.
2704 """
shireenraoa4e29912019-08-24 11:26:41 -04002705 for name in zipfile.Path._implied_dirs(zf.namelist()):
2706 zf.writestr(name, b"")
2707 return zf
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002708
2709
shireenraoa4e29912019-08-24 11:26:41 -04002710def build_alpharep_fixture():
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002711 """
2712 Create a zip file with this structure:
2713
2714 .
2715 ├── a.txt
shireenraoa4e29912019-08-24 11:26:41 -04002716 ├── b
2717 │ ├── c.txt
2718 │ ├── d
2719 │ │ └── e.txt
2720 │ └── f.txt
2721 └── g
2722 └── h
2723 └── i.txt
2724
2725 This fixture has the following key characteristics:
2726
2727 - a file at the root (a)
2728 - a file two levels deep (b/d/e)
2729 - multiple files in a directory (b/c, b/f)
2730 - a directory containing only a directory (g/h)
2731
2732 "alpha" because it uses alphabet
2733 "rep" because it's a representative example
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002734 """
2735 data = io.BytesIO()
2736 zf = zipfile.ZipFile(data, "w")
2737 zf.writestr("a.txt", b"content of a")
2738 zf.writestr("b/c.txt", b"content of c")
2739 zf.writestr("b/d/e.txt", b"content of e")
shireenraoa4e29912019-08-24 11:26:41 -04002740 zf.writestr("b/f.txt", b"content of f")
2741 zf.writestr("g/h/i.txt", b"content of i")
2742 zf.filename = "alpharep.zip"
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002743 return zf
2744
2745
Gregory P. Smith3f4db4a2019-09-10 17:14:11 +01002746class TestExecutablePrependedZip(unittest.TestCase):
2747 """Test our ability to open zip files with an executable prepended."""
2748
2749 def setUp(self):
2750 self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
2751 self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
2752
2753 def _test_zip_works(self, name):
2754 # bpo-28494 sanity check: ensure is_zipfile works on these.
2755 self.assertTrue(zipfile.is_zipfile(name),
2756 f'is_zipfile failed on {name}')
2757 # Ensure we can operate on these via ZipFile.
2758 with zipfile.ZipFile(name) as zipfp:
2759 for n in zipfp.namelist():
2760 data = zipfp.read(n)
2761 self.assertIn(b'FAVORITE_NUMBER', data)
2762
2763 def test_read_zip_with_exe_prepended(self):
2764 self._test_zip_works(self.exe_zip)
2765
2766 def test_read_zip64_with_exe_prepended(self):
2767 self._test_zip_works(self.exe_zip64)
2768
2769 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2770 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2771 'Test relies on #!/bin/bash working.')
2772 def test_execute_zip2(self):
2773 output = subprocess.check_output([self.exe_zip, sys.executable])
2774 self.assertIn(b'number in executable: 5', output)
2775
2776 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2777 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2778 'Test relies on #!/bin/bash working.')
2779 def test_execute_zip64(self):
2780 output = subprocess.check_output([self.exe_zip64, sys.executable])
2781 self.assertIn(b'number in executable: 5', output)
2782
2783
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002784class TestPath(unittest.TestCase):
2785 def setUp(self):
2786 self.fixtures = contextlib.ExitStack()
2787 self.addCleanup(self.fixtures.close)
2788
shireenraoa4e29912019-08-24 11:26:41 -04002789 def zipfile_alpharep(self):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002790 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002791 yield build_alpharep_fixture()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002792 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002793 yield add_dirs(build_alpharep_fixture())
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002794
2795 def zipfile_ondisk(self):
2796 tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
shireenraoa4e29912019-08-24 11:26:41 -04002797 for alpharep in self.zipfile_alpharep():
2798 buffer = alpharep.fp
2799 alpharep.close()
2800 path = tmpdir / alpharep.filename
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002801 with path.open("wb") as strm:
2802 strm.write(buffer.getvalue())
2803 yield path
2804
shireenraoa4e29912019-08-24 11:26:41 -04002805 def test_iterdir_and_types(self):
2806 for alpharep in self.zipfile_alpharep():
2807 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002808 assert root.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002809 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002810 assert a.is_file()
2811 assert b.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002812 assert g.is_dir()
2813 c, f, d = b.iterdir()
2814 assert c.is_file() and f.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002815 e, = d.iterdir()
2816 assert e.is_file()
shireenraoa4e29912019-08-24 11:26:41 -04002817 h, = g.iterdir()
2818 i, = h.iterdir()
2819 assert i.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002820
2821 def test_open(self):
shireenraoa4e29912019-08-24 11:26:41 -04002822 for alpharep in self.zipfile_alpharep():
2823 root = zipfile.Path(alpharep)
2824 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002825 with a.open() as strm:
2826 data = strm.read()
2827 assert data == b"content of a"
2828
2829 def test_read(self):
shireenraoa4e29912019-08-24 11:26:41 -04002830 for alpharep in self.zipfile_alpharep():
2831 root = zipfile.Path(alpharep)
2832 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002833 assert a.read_text() == "content of a"
2834 assert a.read_bytes() == b"content of a"
2835
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002836 def test_joinpath(self):
shireenraoa4e29912019-08-24 11:26:41 -04002837 for alpharep in self.zipfile_alpharep():
2838 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002839 a = root.joinpath("a")
2840 assert a.is_file()
2841 e = root.joinpath("b").joinpath("d").joinpath("e.txt")
2842 assert e.read_text() == "content of e"
2843
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002844 def test_traverse_truediv(self):
shireenraoa4e29912019-08-24 11:26:41 -04002845 for alpharep in self.zipfile_alpharep():
2846 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002847 a = root / "a"
2848 assert a.is_file()
2849 e = root / "b" / "d" / "e.txt"
2850 assert e.read_text() == "content of e"
2851
2852 def test_pathlike_construction(self):
2853 """
2854 zipfile.Path should be constructable from a path-like object
2855 """
2856 for zipfile_ondisk in self.zipfile_ondisk():
2857 pathlike = pathlib.Path(str(zipfile_ondisk))
2858 zipfile.Path(pathlike)
2859
2860 def test_traverse_pathlike(self):
shireenraoa4e29912019-08-24 11:26:41 -04002861 for alpharep in self.zipfile_alpharep():
2862 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002863 root / pathlib.Path("a")
2864
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002865 def test_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002866 for alpharep in self.zipfile_alpharep():
2867 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002868 assert (root / 'a').parent.at == ''
2869 assert (root / 'a' / 'b').parent.at == 'a/'
2870
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002871 def test_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002872 for alpharep in self.zipfile_alpharep():
2873 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002874 assert (root / 'b').parent.at == ''
2875 assert (root / 'b/').parent.at == ''
2876
2877 def test_missing_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002878 for alpharep in self.zipfile_alpharep():
2879 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002880 assert (root / 'missing dir/').parent.at == ''
2881
shireenraoa4e29912019-08-24 11:26:41 -04002882
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00002883if __name__ == "__main__":
Brett Cannond5b4e1d2013-06-12 19:57:19 -04002884 unittest.main()