blob: f03c044eae3a6027df5adea3532ea17f3a1f915b [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
Miss Skeleton (bot)3801b262019-10-29 00:44:07 -07004import 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
Miss Islington (bot)74b02912019-09-10 15:57:54 -07009import subprocess
10import sys
Jason R. Coombsb2758ff2019-05-08 09:45:06 -040011import time
Ezio Melotti74c96ec2009-07-08 22:24:06 +000012import unittest
Miss Islington (bot)717cc612019-09-12 07:33:53 -070013import 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
Miss Skeleton (bot)3801b262019-10-29 00:44:07 -0700828 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. Smithb0d9ca922009-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
Gregory P. Smith0af8a862014-05-29 23:42:14 -07001883 def test_zipfile_with_short_extra_field(self):
1884 """If an extra field in the header is less than 4 bytes, skip it."""
1885 zipdata = (
1886 b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1887 b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1888 b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1889 b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1890 b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1891 b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1892 b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1893 )
1894 with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1895 # testzip returns the name of the first corrupt file, or None
1896 self.assertIsNone(zipf.testzip())
1897
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001898 def test_open_conflicting_handles(self):
1899 # It's only possible to open one writable file handle at a time
1900 msg1 = b"It's fun to charter an accountant!"
1901 msg2 = b"And sail the wide accountant sea"
1902 msg3 = b"To find, explore the funds offshore"
1903 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
1904 with zipf.open('foo', mode='w') as w2:
1905 w2.write(msg1)
1906 with zipf.open('bar', mode='w') as w1:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001907 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001908 zipf.open('handle', mode='w')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001909 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001910 zipf.open('foo', mode='r')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001911 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001912 zipf.writestr('str', 'abcde')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001913 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001914 zipf.write(__file__, 'file')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001915 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001916 zipf.close()
1917 w1.write(msg2)
1918 with zipf.open('baz', mode='w') as w2:
1919 w2.write(msg3)
1920
1921 with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1922 self.assertEqual(zipf.read('foo'), msg1)
1923 self.assertEqual(zipf.read('bar'), msg2)
1924 self.assertEqual(zipf.read('baz'), msg3)
1925 self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
1926
John Jolly066df4f2018-01-30 01:51:35 -07001927 def test_seek_tell(self):
1928 # Test seek functionality
1929 txt = b"Where's Bruce?"
1930 bloc = txt.find(b"Bruce")
1931 # Check seek on a file
1932 with zipfile.ZipFile(TESTFN, "w") as zipf:
1933 zipf.writestr("foo.txt", txt)
1934 with zipfile.ZipFile(TESTFN, "r") as zipf:
1935 with zipf.open("foo.txt", "r") as fp:
1936 fp.seek(bloc, os.SEEK_SET)
1937 self.assertEqual(fp.tell(), bloc)
1938 fp.seek(-bloc, os.SEEK_CUR)
1939 self.assertEqual(fp.tell(), 0)
1940 fp.seek(bloc, os.SEEK_CUR)
1941 self.assertEqual(fp.tell(), bloc)
1942 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1943 fp.seek(0, os.SEEK_END)
1944 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001945 fp.seek(0, os.SEEK_SET)
1946 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07001947 # Check seek on memory file
1948 data = io.BytesIO()
1949 with zipfile.ZipFile(data, mode="w") as zipf:
1950 zipf.writestr("foo.txt", txt)
1951 with zipfile.ZipFile(data, mode="r") as zipf:
1952 with zipf.open("foo.txt", "r") as fp:
1953 fp.seek(bloc, os.SEEK_SET)
1954 self.assertEqual(fp.tell(), bloc)
1955 fp.seek(-bloc, os.SEEK_CUR)
1956 self.assertEqual(fp.tell(), 0)
1957 fp.seek(bloc, os.SEEK_CUR)
1958 self.assertEqual(fp.tell(), bloc)
1959 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1960 fp.seek(0, os.SEEK_END)
1961 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001962 fp.seek(0, os.SEEK_SET)
1963 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07001964
Miss Islington (bot)717cc612019-09-12 07:33:53 -07001965 @requires_bz2
1966 def test_decompress_without_3rd_party_library(self):
1967 data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1968 zip_file = io.BytesIO(data)
1969 with zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_BZIP2) as zf:
1970 zf.writestr('a.txt', b'a')
1971 with mock.patch('zipfile.bz2', None):
1972 with zipfile.ZipFile(zip_file) as zf:
1973 self.assertRaises(RuntimeError, zf.extract, 'a.txt')
1974
Guido van Rossumd8faa362007-04-27 19:54:29 +00001975 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00001976 unlink(TESTFN)
1977 unlink(TESTFN2)
1978
Thomas Wouterscf297e42007-02-23 15:07:44 +00001979
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001980class AbstractBadCrcTests:
1981 def test_testzip_with_bad_crc(self):
1982 """Tests that files with bad CRCs return their name from testzip."""
1983 zipdata = self.zip_with_bad_crc
1984
1985 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1986 # testzip returns the name of the first corrupt file, or None
1987 self.assertEqual('afile', zipf.testzip())
1988
1989 def test_read_with_bad_crc(self):
1990 """Tests that files with bad CRCs raise a BadZipFile exception when read."""
1991 zipdata = self.zip_with_bad_crc
1992
1993 # Using ZipFile.read()
1994 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1995 self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile')
1996
1997 # Using ZipExtFile.read()
1998 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1999 with zipf.open('afile', 'r') as corrupt_file:
2000 self.assertRaises(zipfile.BadZipFile, corrupt_file.read)
2001
2002 # Same with small reads (in order to exercise the buffering logic)
2003 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2004 with zipf.open('afile', 'r') as corrupt_file:
2005 corrupt_file.MIN_READ_SIZE = 2
2006 with self.assertRaises(zipfile.BadZipFile):
2007 while corrupt_file.read(2):
2008 pass
2009
2010
2011class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2012 compression = zipfile.ZIP_STORED
2013 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002014 b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
2015 b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
2016 b'ilehello,AworldP'
2017 b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
2018 b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
2019 b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
2020 b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
2021 b'\0\0/\0\0\0\0\0')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002022
2023@requires_zlib
2024class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2025 compression = zipfile.ZIP_DEFLATED
2026 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002027 b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
2028 b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2029 b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
2030 b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
2031 b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
2032 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
2033 b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
2034 b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002035
2036@requires_bz2
2037class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2038 compression = zipfile.ZIP_BZIP2
2039 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002040 b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA'
2041 b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2042 b'ileBZh91AY&SY\xd4\xa8\xca'
2043 b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5'
2044 b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f'
2045 b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14'
2046 b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8'
2047 b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'
2048 b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK'
2049 b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00'
2050 b'\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002051
2052@requires_lzma
2053class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2054 compression = zipfile.ZIP_LZMA
2055 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002056 b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2057 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2058 b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I'
2059 b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK'
2060 b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2061 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00'
2062 b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil'
2063 b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
2064 b'\x00>\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002065
2066
Thomas Wouterscf297e42007-02-23 15:07:44 +00002067class DecryptionTests(unittest.TestCase):
Ezio Melotti35386712009-12-31 13:22:41 +00002068 """Check that ZIP decryption works. Since the library does not
2069 support encryption at the moment, we use a pre-generated encrypted
2070 ZIP file."""
Thomas Wouterscf297e42007-02-23 15:07:44 +00002071
2072 data = (
Christian Tismer59202e52013-10-21 03:59:23 +02002073 b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
2074 b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
2075 b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
2076 b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
2077 b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
2078 b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
2079 b'\x00\x00L\x00\x00\x00\x00\x00' )
Christian Heimesfdab48e2008-01-20 09:06:41 +00002080 data2 = (
Christian Tismer59202e52013-10-21 03:59:23 +02002081 b'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
2082 b'\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
2083 b'\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
2084 b'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
2085 b'\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
2086 b'\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
2087 b'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
2088 b'\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
Thomas Wouterscf297e42007-02-23 15:07:44 +00002089
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002090 plain = b'zipfile.py encryption test'
Christian Heimesfdab48e2008-01-20 09:06:41 +00002091 plain2 = b'\x00'*512
Thomas Wouterscf297e42007-02-23 15:07:44 +00002092
2093 def setUp(self):
Ezio Melotti35386712009-12-31 13:22:41 +00002094 with open(TESTFN, "wb") as fp:
2095 fp.write(self.data)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002096 self.zip = zipfile.ZipFile(TESTFN, "r")
Ezio Melotti35386712009-12-31 13:22:41 +00002097 with open(TESTFN2, "wb") as fp:
2098 fp.write(self.data2)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002099 self.zip2 = zipfile.ZipFile(TESTFN2, "r")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002100
2101 def tearDown(self):
2102 self.zip.close()
2103 os.unlink(TESTFN)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002104 self.zip2.close()
2105 os.unlink(TESTFN2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002106
Ezio Melottiafd0d112009-07-15 17:17:17 +00002107 def test_no_password(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00002108 # Reading the encrypted file without password
2109 # must generate a RunTime exception
2110 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002111 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002112
Ezio Melottiafd0d112009-07-15 17:17:17 +00002113 def test_bad_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002114 self.zip.setpassword(b"perl")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002115 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002116 self.zip2.setpassword(b"perl")
2117 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Guido van Rossumd8faa362007-04-27 19:54:29 +00002118
Ezio Melotti975077a2011-05-19 22:03:22 +03002119 @requires_zlib
Ezio Melottiafd0d112009-07-15 17:17:17 +00002120 def test_good_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002121 self.zip.setpassword(b"python")
Ezio Melotti35386712009-12-31 13:22:41 +00002122 self.assertEqual(self.zip.read("test.txt"), self.plain)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002123 self.zip2.setpassword(b"12345")
Ezio Melotti35386712009-12-31 13:22:41 +00002124 self.assertEqual(self.zip2.read("zero"), self.plain2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002125
R. David Murray8d855d82010-12-21 21:53:37 +00002126 def test_unicode_password(self):
2127 self.assertRaises(TypeError, self.zip.setpassword, "unicode")
2128 self.assertRaises(TypeError, self.zip.read, "test.txt", "python")
2129 self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python")
2130 self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python")
2131
Miss Skeleton (bot)76fbdaa2019-10-27 01:40:44 -07002132 def test_seek_tell(self):
2133 self.zip.setpassword(b"python")
2134 txt = self.plain
2135 test_word = b'encryption'
2136 bloc = txt.find(test_word)
2137 bloc_len = len(test_word)
2138 with self.zip.open("test.txt", "r") as fp:
2139 fp.seek(bloc, os.SEEK_SET)
2140 self.assertEqual(fp.tell(), bloc)
2141 fp.seek(-bloc, os.SEEK_CUR)
2142 self.assertEqual(fp.tell(), 0)
2143 fp.seek(bloc, os.SEEK_CUR)
2144 self.assertEqual(fp.tell(), bloc)
2145 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2146
2147 # Make sure that the second read after seeking back beyond
2148 # _readbuffer returns the same content (ie. rewind to the start of
2149 # the file to read forward to the required position).
2150 old_read_size = fp.MIN_READ_SIZE
2151 fp.MIN_READ_SIZE = 1
2152 fp._readbuffer = b''
2153 fp._offset = 0
2154 fp.seek(0, os.SEEK_SET)
2155 self.assertEqual(fp.tell(), 0)
2156 fp.seek(bloc, os.SEEK_CUR)
2157 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2158 fp.MIN_READ_SIZE = old_read_size
2159
2160 fp.seek(0, os.SEEK_END)
2161 self.assertEqual(fp.tell(), len(txt))
2162 fp.seek(0, os.SEEK_SET)
2163 self.assertEqual(fp.tell(), 0)
2164
2165 # Read the file completely to definitely call any eof integrity
2166 # checks (crc) and make sure they still pass.
2167 fp.read()
2168
2169
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002170class AbstractTestsWithRandomBinaryFiles:
2171 @classmethod
2172 def setUpClass(cls):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002173 datacount = randint(16, 64)*1024 + randint(1, 1024)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002174 cls.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
2175 for i in range(datacount))
Guido van Rossumd8faa362007-04-27 19:54:29 +00002176
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002177 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002178 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +00002179 with open(TESTFN, "wb") as fp:
2180 fp.write(self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002181
2182 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002183 unlink(TESTFN)
2184 unlink(TESTFN2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002185
Ezio Melottiafd0d112009-07-15 17:17:17 +00002186 def make_test_archive(self, f, compression):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002187 # Create the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002188 with zipfile.ZipFile(f, "w", compression) as zipfp:
2189 zipfp.write(TESTFN, "another.name")
2190 zipfp.write(TESTFN, TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002191
Ezio Melottiafd0d112009-07-15 17:17:17 +00002192 def zip_test(self, f, compression):
2193 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002194
2195 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002196 with zipfile.ZipFile(f, "r", compression) as zipfp:
2197 testdata = zipfp.read(TESTFN)
2198 self.assertEqual(len(testdata), len(self.data))
2199 self.assertEqual(testdata, self.data)
2200 self.assertEqual(zipfp.read("another.name"), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002201
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002202 def test_read(self):
2203 for f in get_files(self):
2204 self.zip_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002205
Ezio Melottiafd0d112009-07-15 17:17:17 +00002206 def zip_open_test(self, f, compression):
2207 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002208
2209 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002210 with zipfile.ZipFile(f, "r", compression) as zipfp:
2211 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002212 with zipfp.open(TESTFN) as zipopen1:
2213 while True:
2214 read_data = zipopen1.read(256)
2215 if not read_data:
2216 break
2217 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002218
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002219 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002220 with zipfp.open("another.name") as zipopen2:
2221 while True:
2222 read_data = zipopen2.read(256)
2223 if not read_data:
2224 break
2225 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002226
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002227 testdata1 = b''.join(zipdata1)
2228 self.assertEqual(len(testdata1), len(self.data))
2229 self.assertEqual(testdata1, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002230
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002231 testdata2 = b''.join(zipdata2)
Ezio Melotti35386712009-12-31 13:22:41 +00002232 self.assertEqual(len(testdata2), len(self.data))
2233 self.assertEqual(testdata2, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002234
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002235 def test_open(self):
2236 for f in get_files(self):
2237 self.zip_open_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002238
Ezio Melottiafd0d112009-07-15 17:17:17 +00002239 def zip_random_open_test(self, f, compression):
2240 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002241
2242 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002243 with zipfile.ZipFile(f, "r", compression) as zipfp:
2244 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002245 with zipfp.open(TESTFN) as zipopen1:
2246 while True:
2247 read_data = zipopen1.read(randint(1, 1024))
2248 if not read_data:
2249 break
2250 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002251
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002252 testdata = b''.join(zipdata1)
2253 self.assertEqual(len(testdata), len(self.data))
2254 self.assertEqual(testdata, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002255
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002256 def test_random_open(self):
2257 for f in get_files(self):
2258 self.zip_random_open_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002259
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00002260
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002261class StoredTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2262 unittest.TestCase):
2263 compression = zipfile.ZIP_STORED
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02002264
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002265@requires_zlib
2266class DeflateTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2267 unittest.TestCase):
2268 compression = zipfile.ZIP_DEFLATED
2269
2270@requires_bz2
2271class Bzip2TestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2272 unittest.TestCase):
2273 compression = zipfile.ZIP_BZIP2
2274
2275@requires_lzma
2276class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2277 unittest.TestCase):
2278 compression = zipfile.ZIP_LZMA
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002279
Ezio Melotti76430242009-07-11 18:28:48 +00002280
luzpaza5293b42017-11-05 07:37:50 -06002281# Provide the tell() method but not seek()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002282class Tellable:
2283 def __init__(self, fp):
2284 self.fp = fp
2285 self.offset = 0
2286
2287 def write(self, data):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002288 n = self.fp.write(data)
2289 self.offset += n
2290 return n
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002291
2292 def tell(self):
2293 return self.offset
2294
2295 def flush(self):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002296 self.fp.flush()
2297
2298class Unseekable:
2299 def __init__(self, fp):
2300 self.fp = fp
2301
2302 def write(self, data):
2303 return self.fp.write(data)
2304
2305 def flush(self):
2306 self.fp.flush()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002307
2308class UnseekableTests(unittest.TestCase):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002309 def test_writestr(self):
2310 for wrapper in (lambda f: f), Tellable, Unseekable:
2311 with self.subTest(wrapper=wrapper):
2312 f = io.BytesIO()
2313 f.write(b'abc')
2314 bf = io.BufferedWriter(f)
2315 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2316 zipfp.writestr('ones', b'111')
2317 zipfp.writestr('twos', b'222')
2318 self.assertEqual(f.getvalue()[:5], b'abcPK')
2319 with zipfile.ZipFile(f, mode='r') as zipf:
2320 with zipf.open('ones') as zopen:
2321 self.assertEqual(zopen.read(), b'111')
2322 with zipf.open('twos') as zopen:
2323 self.assertEqual(zopen.read(), b'222')
2324
2325 def test_write(self):
2326 for wrapper in (lambda f: f), Tellable, Unseekable:
2327 with self.subTest(wrapper=wrapper):
2328 f = io.BytesIO()
2329 f.write(b'abc')
2330 bf = io.BufferedWriter(f)
2331 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2332 self.addCleanup(unlink, TESTFN)
2333 with open(TESTFN, 'wb') as f2:
2334 f2.write(b'111')
2335 zipfp.write(TESTFN, 'ones')
2336 with open(TESTFN, 'wb') as f2:
2337 f2.write(b'222')
2338 zipfp.write(TESTFN, 'twos')
2339 self.assertEqual(f.getvalue()[:5], b'abcPK')
2340 with zipfile.ZipFile(f, mode='r') as zipf:
2341 with zipf.open('ones') as zopen:
2342 self.assertEqual(zopen.read(), b'111')
2343 with zipf.open('twos') as zopen:
2344 self.assertEqual(zopen.read(), b'222')
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002345
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002346 def test_open_write(self):
2347 for wrapper in (lambda f: f), Tellable, Unseekable:
2348 with self.subTest(wrapper=wrapper):
2349 f = io.BytesIO()
2350 f.write(b'abc')
2351 bf = io.BufferedWriter(f)
2352 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
2353 with zipf.open('ones', 'w') as zopen:
2354 zopen.write(b'111')
2355 with zipf.open('twos', 'w') as zopen:
2356 zopen.write(b'222')
2357 self.assertEqual(f.getvalue()[:5], b'abcPK')
2358 with zipfile.ZipFile(f) as zipf:
2359 self.assertEqual(zipf.read('ones'), b'111')
2360 self.assertEqual(zipf.read('twos'), b'222')
2361
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002362
Ezio Melotti975077a2011-05-19 22:03:22 +03002363@requires_zlib
Guido van Rossumd8faa362007-04-27 19:54:29 +00002364class TestsWithMultipleOpens(unittest.TestCase):
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002365 @classmethod
2366 def setUpClass(cls):
2367 cls.data1 = b'111' + getrandbytes(10000)
2368 cls.data2 = b'222' + getrandbytes(10000)
2369
2370 def make_test_archive(self, f):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002371 # Create the ZIP archive
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002372 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
2373 zipfp.writestr('ones', self.data1)
2374 zipfp.writestr('twos', self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002375
Ezio Melottiafd0d112009-07-15 17:17:17 +00002376 def test_same_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002377 # Verify that (when the ZipFile is in control of creating file objects)
2378 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002379 for f in get_files(self):
2380 self.make_test_archive(f)
2381 with zipfile.ZipFile(f, mode="r") as zipf:
2382 with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
2383 data1 = zopen1.read(500)
2384 data2 = zopen2.read(500)
2385 data1 += zopen1.read()
2386 data2 += zopen2.read()
2387 self.assertEqual(data1, data2)
2388 self.assertEqual(data1, self.data1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002389
Ezio Melottiafd0d112009-07-15 17:17:17 +00002390 def test_different_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002391 # Verify that (when the ZipFile is in control of creating file objects)
2392 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002393 for f in get_files(self):
2394 self.make_test_archive(f)
2395 with zipfile.ZipFile(f, mode="r") as zipf:
2396 with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
2397 data1 = zopen1.read(500)
2398 data2 = zopen2.read(500)
2399 data1 += zopen1.read()
2400 data2 += zopen2.read()
2401 self.assertEqual(data1, self.data1)
2402 self.assertEqual(data2, self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002403
Ezio Melottiafd0d112009-07-15 17:17:17 +00002404 def test_interleaved(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002405 # Verify that (when the ZipFile is in control of creating file objects)
2406 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002407 for f in get_files(self):
2408 self.make_test_archive(f)
2409 with zipfile.ZipFile(f, mode="r") as zipf:
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002410 with zipf.open('ones') as zopen1:
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002411 data1 = zopen1.read(500)
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002412 with zipf.open('twos') as zopen2:
2413 data2 = zopen2.read(500)
2414 data1 += zopen1.read()
2415 data2 += zopen2.read()
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002416 self.assertEqual(data1, self.data1)
2417 self.assertEqual(data2, self.data2)
2418
2419 def test_read_after_close(self):
2420 for f in get_files(self):
2421 self.make_test_archive(f)
2422 with contextlib.ExitStack() as stack:
2423 with zipfile.ZipFile(f, 'r') as zipf:
2424 zopen1 = stack.enter_context(zipf.open('ones'))
2425 zopen2 = stack.enter_context(zipf.open('twos'))
Brian Curtin8fb9b862010-11-18 02:15:28 +00002426 data1 = zopen1.read(500)
2427 data2 = zopen2.read(500)
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002428 data1 += zopen1.read()
2429 data2 += zopen2.read()
2430 self.assertEqual(data1, self.data1)
2431 self.assertEqual(data2, self.data2)
2432
2433 def test_read_after_write(self):
2434 for f in get_files(self):
2435 with zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as zipf:
2436 zipf.writestr('ones', self.data1)
2437 zipf.writestr('twos', self.data2)
2438 with zipf.open('ones') as zopen1:
2439 data1 = zopen1.read(500)
2440 self.assertEqual(data1, self.data1[:500])
2441 with zipfile.ZipFile(f, 'r') as zipf:
2442 data1 = zipf.read('ones')
2443 data2 = zipf.read('twos')
2444 self.assertEqual(data1, self.data1)
2445 self.assertEqual(data2, self.data2)
2446
2447 def test_write_after_read(self):
2448 for f in get_files(self):
2449 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipf:
2450 zipf.writestr('ones', self.data1)
2451 with zipf.open('ones') as zopen1:
2452 zopen1.read(500)
2453 zipf.writestr('twos', self.data2)
2454 with zipfile.ZipFile(f, 'r') as zipf:
2455 data1 = zipf.read('ones')
2456 data2 = zipf.read('twos')
2457 self.assertEqual(data1, self.data1)
2458 self.assertEqual(data2, self.data2)
2459
2460 def test_many_opens(self):
2461 # Verify that read() and open() promptly close the file descriptor,
2462 # and don't rely on the garbage collector to free resources.
2463 self.make_test_archive(TESTFN2)
2464 with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
2465 for x in range(100):
2466 zipf.read('ones')
2467 with zipf.open('ones') as zopen1:
2468 pass
2469 with open(os.devnull) as f:
2470 self.assertLess(f.fileno(), 100)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002471
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002472 def test_write_while_reading(self):
2473 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
2474 zipf.writestr('ones', self.data1)
2475 with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
2476 with zipf.open('ones', 'r') as r1:
2477 data1 = r1.read(500)
2478 with zipf.open('twos', 'w') as w1:
2479 w1.write(self.data2)
2480 data1 += r1.read()
2481 self.assertEqual(data1, self.data1)
2482 with zipfile.ZipFile(TESTFN2) as zipf:
2483 self.assertEqual(zipf.read('twos'), self.data2)
2484
Guido van Rossumd8faa362007-04-27 19:54:29 +00002485 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002486 unlink(TESTFN2)
2487
Guido van Rossumd8faa362007-04-27 19:54:29 +00002488
Martin v. Löwis59e47792009-01-24 14:10:07 +00002489class TestWithDirectory(unittest.TestCase):
2490 def setUp(self):
2491 os.mkdir(TESTFN2)
2492
Ezio Melottiafd0d112009-07-15 17:17:17 +00002493 def test_extract_dir(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002494 with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
2495 zipf.extractall(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002496 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
2497 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
2498 self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
2499
Ezio Melottiafd0d112009-07-15 17:17:17 +00002500 def test_bug_6050(self):
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002501 # Extraction should succeed if directories already exist
2502 os.mkdir(os.path.join(TESTFN2, "a"))
Ezio Melottiafd0d112009-07-15 17:17:17 +00002503 self.test_extract_dir()
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002504
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002505 def test_write_dir(self):
2506 dirpath = os.path.join(TESTFN2, "x")
2507 os.mkdir(dirpath)
2508 mode = os.stat(dirpath).st_mode & 0xFFFF
2509 with zipfile.ZipFile(TESTFN, "w") as zipf:
2510 zipf.write(dirpath)
2511 zinfo = zipf.filelist[0]
2512 self.assertTrue(zinfo.filename.endswith("/x/"))
2513 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2514 zipf.write(dirpath, "y")
2515 zinfo = zipf.filelist[1]
2516 self.assertTrue(zinfo.filename, "y/")
2517 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2518 with zipfile.ZipFile(TESTFN, "r") as zipf:
2519 zinfo = zipf.filelist[0]
2520 self.assertTrue(zinfo.filename.endswith("/x/"))
2521 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2522 zinfo = zipf.filelist[1]
2523 self.assertTrue(zinfo.filename, "y/")
2524 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2525 target = os.path.join(TESTFN2, "target")
2526 os.mkdir(target)
2527 zipf.extractall(target)
2528 self.assertTrue(os.path.isdir(os.path.join(target, "y")))
2529 self.assertEqual(len(os.listdir(target)), 2)
2530
2531 def test_writestr_dir(self):
Martin v. Löwis59e47792009-01-24 14:10:07 +00002532 os.mkdir(os.path.join(TESTFN2, "x"))
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002533 with zipfile.ZipFile(TESTFN, "w") as zipf:
2534 zipf.writestr("x/", b'')
2535 zinfo = zipf.filelist[0]
2536 self.assertEqual(zinfo.filename, "x/")
2537 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2538 with zipfile.ZipFile(TESTFN, "r") as zipf:
2539 zinfo = zipf.filelist[0]
2540 self.assertTrue(zinfo.filename.endswith("x/"))
2541 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2542 target = os.path.join(TESTFN2, "target")
2543 os.mkdir(target)
2544 zipf.extractall(target)
2545 self.assertTrue(os.path.isdir(os.path.join(target, "x")))
2546 self.assertEqual(os.listdir(target), ["x"])
Martin v. Löwis59e47792009-01-24 14:10:07 +00002547
2548 def tearDown(self):
Victor Stinner57004c62014-09-04 00:49:01 +02002549 rmtree(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002550 if os.path.exists(TESTFN):
Ezio Melotti76430242009-07-11 18:28:48 +00002551 unlink(TESTFN)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002552
Guido van Rossumd8faa362007-04-27 19:54:29 +00002553
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002554class ZipInfoTests(unittest.TestCase):
2555 def test_from_file(self):
2556 zi = zipfile.ZipInfo.from_file(__file__)
2557 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2558 self.assertFalse(zi.is_dir())
Serhiy Storchaka8606e952017-03-08 14:37:51 +02002559 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2560
2561 def test_from_file_pathlike(self):
2562 zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
2563 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2564 self.assertFalse(zi.is_dir())
2565 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2566
2567 def test_from_file_bytes(self):
2568 zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
2569 self.assertEqual(posixpath.basename(zi.filename), 'test')
2570 self.assertFalse(zi.is_dir())
2571 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2572
2573 def test_from_file_fileno(self):
2574 with open(__file__, 'rb') as f:
2575 zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
2576 self.assertEqual(posixpath.basename(zi.filename), 'test')
2577 self.assertFalse(zi.is_dir())
2578 self.assertEqual(zi.file_size, os.path.getsize(__file__))
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002579
2580 def test_from_dir(self):
2581 dirpath = os.path.dirname(os.path.abspath(__file__))
2582 zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
2583 self.assertEqual(zi.filename, 'stdlib_tests/')
2584 self.assertTrue(zi.is_dir())
2585 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
2586 self.assertEqual(zi.file_size, 0)
2587
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002588
2589class CommandLineTest(unittest.TestCase):
2590
2591 def zipfilecmd(self, *args, **kwargs):
2592 rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args,
2593 **kwargs)
2594 return out.replace(os.linesep.encode(), b'\n')
2595
2596 def zipfilecmd_failure(self, *args):
2597 return script_helper.assert_python_failure('-m', 'zipfile', *args)
2598
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002599 def test_bad_use(self):
2600 rc, out, err = self.zipfilecmd_failure()
2601 self.assertEqual(out, b'')
2602 self.assertIn(b'usage', err.lower())
2603 self.assertIn(b'error', err.lower())
2604 self.assertIn(b'required', err.lower())
2605 rc, out, err = self.zipfilecmd_failure('-l', '')
2606 self.assertEqual(out, b'')
2607 self.assertNotEqual(err.strip(), b'')
2608
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002609 def test_test_command(self):
2610 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002611 for opt in '-t', '--test':
2612 out = self.zipfilecmd(opt, zip_name)
2613 self.assertEqual(out.rstrip(), b'Done testing')
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002614 zip_name = findfile('testtar.tar')
2615 rc, out, err = self.zipfilecmd_failure('-t', zip_name)
2616 self.assertEqual(out, b'')
2617
2618 def test_list_command(self):
2619 zip_name = findfile('zipdir.zip')
2620 t = io.StringIO()
2621 with zipfile.ZipFile(zip_name, 'r') as tf:
2622 tf.printdir(t)
2623 expected = t.getvalue().encode('ascii', 'backslashreplace')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002624 for opt in '-l', '--list':
2625 out = self.zipfilecmd(opt, zip_name,
2626 PYTHONIOENCODING='ascii:backslashreplace')
2627 self.assertEqual(out, expected)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002628
Serhiy Storchakab4293ef2016-10-23 22:32:30 +03002629 @requires_zlib
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002630 def test_create_command(self):
2631 self.addCleanup(unlink, TESTFN)
2632 with open(TESTFN, 'w') as f:
2633 f.write('test 1')
2634 os.mkdir(TESTFNDIR)
2635 self.addCleanup(rmtree, TESTFNDIR)
2636 with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f:
2637 f.write('test 2')
2638 files = [TESTFN, TESTFNDIR]
2639 namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt']
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002640 for opt in '-c', '--create':
2641 try:
2642 out = self.zipfilecmd(opt, TESTFN2, *files)
2643 self.assertEqual(out, b'')
2644 with zipfile.ZipFile(TESTFN2) as zf:
2645 self.assertEqual(zf.namelist(), namelist)
2646 self.assertEqual(zf.read(namelist[0]), b'test 1')
2647 self.assertEqual(zf.read(namelist[2]), b'test 2')
2648 finally:
2649 unlink(TESTFN2)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002650
2651 def test_extract_command(self):
2652 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002653 for opt in '-e', '--extract':
2654 with temp_dir() as extdir:
2655 out = self.zipfilecmd(opt, zip_name, extdir)
2656 self.assertEqual(out, b'')
2657 with zipfile.ZipFile(zip_name) as zf:
2658 for zi in zf.infolist():
2659 path = os.path.join(extdir,
2660 zi.filename.replace('/', os.sep))
2661 if zi.is_dir():
2662 self.assertTrue(os.path.isdir(path))
2663 else:
2664 self.assertTrue(os.path.isfile(path))
2665 with open(path, 'rb') as f:
2666 self.assertEqual(f.read(), zf.read(zi))
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002667
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002668
2669# Poor man's technique to consume a (smallish) iterable.
2670consume = tuple
2671
2672
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002673def add_dirs(zf):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002674 """
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002675 Given a writable zip file zf, inject directory entries for
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002676 any directories implied by the presence of children.
2677 """
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002678 for name in zipfile.Path._implied_dirs(zf.namelist()):
2679 zf.writestr(name, b"")
2680 return zf
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002681
2682
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002683def build_alpharep_fixture():
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002684 """
2685 Create a zip file with this structure:
2686
2687 .
2688 ├── a.txt
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002689 ├── b
2690 │ ├── c.txt
2691 │ ├── d
2692 │ │ └── e.txt
2693 │ └── f.txt
2694 └── g
2695 └── h
2696 └── i.txt
2697
2698 This fixture has the following key characteristics:
2699
2700 - a file at the root (a)
2701 - a file two levels deep (b/d/e)
2702 - multiple files in a directory (b/c, b/f)
2703 - a directory containing only a directory (g/h)
2704
2705 "alpha" because it uses alphabet
2706 "rep" because it's a representative example
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002707 """
2708 data = io.BytesIO()
2709 zf = zipfile.ZipFile(data, "w")
2710 zf.writestr("a.txt", b"content of a")
2711 zf.writestr("b/c.txt", b"content of c")
2712 zf.writestr("b/d/e.txt", b"content of e")
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002713 zf.writestr("b/f.txt", b"content of f")
2714 zf.writestr("g/h/i.txt", b"content of i")
2715 zf.filename = "alpharep.zip"
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002716 return zf
2717
2718
Miss Islington (bot)74b02912019-09-10 15:57:54 -07002719class TestExecutablePrependedZip(unittest.TestCase):
2720 """Test our ability to open zip files with an executable prepended."""
2721
2722 def setUp(self):
2723 self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
2724 self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
2725
2726 def _test_zip_works(self, name):
2727 # bpo-28494 sanity check: ensure is_zipfile works on these.
2728 self.assertTrue(zipfile.is_zipfile(name),
2729 f'is_zipfile failed on {name}')
2730 # Ensure we can operate on these via ZipFile.
2731 with zipfile.ZipFile(name) as zipfp:
2732 for n in zipfp.namelist():
2733 data = zipfp.read(n)
2734 self.assertIn(b'FAVORITE_NUMBER', data)
2735
2736 def test_read_zip_with_exe_prepended(self):
2737 self._test_zip_works(self.exe_zip)
2738
2739 def test_read_zip64_with_exe_prepended(self):
2740 self._test_zip_works(self.exe_zip64)
2741
2742 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2743 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2744 'Test relies on #!/bin/bash working.')
2745 def test_execute_zip2(self):
2746 output = subprocess.check_output([self.exe_zip, sys.executable])
2747 self.assertIn(b'number in executable: 5', output)
2748
2749 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2750 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2751 'Test relies on #!/bin/bash working.')
2752 def test_execute_zip64(self):
2753 output = subprocess.check_output([self.exe_zip64, sys.executable])
2754 self.assertIn(b'number in executable: 5', output)
2755
2756
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002757class TestPath(unittest.TestCase):
2758 def setUp(self):
2759 self.fixtures = contextlib.ExitStack()
2760 self.addCleanup(self.fixtures.close)
2761
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002762 def zipfile_alpharep(self):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002763 with self.subTest():
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002764 yield build_alpharep_fixture()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002765 with self.subTest():
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002766 yield add_dirs(build_alpharep_fixture())
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002767
2768 def zipfile_ondisk(self):
2769 tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002770 for alpharep in self.zipfile_alpharep():
2771 buffer = alpharep.fp
2772 alpharep.close()
2773 path = tmpdir / alpharep.filename
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002774 with path.open("wb") as strm:
2775 strm.write(buffer.getvalue())
2776 yield path
2777
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002778 def test_iterdir_and_types(self):
2779 for alpharep in self.zipfile_alpharep():
2780 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002781 assert root.is_dir()
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002782 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002783 assert a.is_file()
2784 assert b.is_dir()
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002785 assert g.is_dir()
2786 c, f, d = b.iterdir()
2787 assert c.is_file() and f.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002788 e, = d.iterdir()
2789 assert e.is_file()
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002790 h, = g.iterdir()
2791 i, = h.iterdir()
2792 assert i.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002793
2794 def test_open(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002795 for alpharep in self.zipfile_alpharep():
2796 root = zipfile.Path(alpharep)
2797 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002798 with a.open() as strm:
2799 data = strm.read()
2800 assert data == b"content of a"
2801
2802 def test_read(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002803 for alpharep in self.zipfile_alpharep():
2804 root = zipfile.Path(alpharep)
2805 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002806 assert a.read_text() == "content of a"
2807 assert a.read_bytes() == b"content of a"
2808
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002809 def test_joinpath(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002810 for alpharep in self.zipfile_alpharep():
2811 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002812 a = root.joinpath("a")
2813 assert a.is_file()
2814 e = root.joinpath("b").joinpath("d").joinpath("e.txt")
2815 assert e.read_text() == "content of e"
2816
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002817 def test_traverse_truediv(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002818 for alpharep in self.zipfile_alpharep():
2819 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002820 a = root / "a"
2821 assert a.is_file()
2822 e = root / "b" / "d" / "e.txt"
2823 assert e.read_text() == "content of e"
2824
2825 def test_pathlike_construction(self):
2826 """
2827 zipfile.Path should be constructable from a path-like object
2828 """
2829 for zipfile_ondisk in self.zipfile_ondisk():
2830 pathlike = pathlib.Path(str(zipfile_ondisk))
2831 zipfile.Path(pathlike)
2832
2833 def test_traverse_pathlike(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002834 for alpharep in self.zipfile_alpharep():
2835 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002836 root / pathlib.Path("a")
2837
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002838 def test_parent(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002839 for alpharep in self.zipfile_alpharep():
2840 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002841 assert (root / 'a').parent.at == ''
2842 assert (root / 'a' / 'b').parent.at == 'a/'
2843
Miss Islington (bot)66905d12019-07-07 15:05:53 -07002844 def test_dir_parent(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002845 for alpharep in self.zipfile_alpharep():
2846 root = zipfile.Path(alpharep)
Miss Islington (bot)66905d12019-07-07 15:05:53 -07002847 assert (root / 'b').parent.at == ''
2848 assert (root / 'b/').parent.at == ''
2849
2850 def test_missing_dir_parent(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002851 for alpharep in self.zipfile_alpharep():
2852 root = zipfile.Path(alpharep)
Miss Islington (bot)66905d12019-07-07 15:05:53 -07002853 assert (root / 'missing dir/').parent.at == ''
2854
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002855
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00002856if __name__ == "__main__":
Brett Cannond5b4e1d2013-06-12 19:57:19 -04002857 unittest.main()