blob: c65de9202c0c4b1b45b01ae2a6e9dd7658531791 [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
Miss Islington (bot)b8416332020-01-30 07:05:08 -0800600 ts = 4386268800
Marcel Plch7b41dba2018-08-03 17:59:19 +0200601 try:
Miss Islington (bot)b8416332020-01-30 07:05:08 -0800602 time.localtime(ts)
603 except OverflowError:
604 self.skipTest(f'time.localtime({ts}) raises OverflowError')
605 try:
606 os.utime(TESTFN, (ts, ts))
Marcel Plch7b41dba2018-08-03 17:59:19 +0200607 except OverflowError:
608 self.skipTest('Host fs cannot set timestamp to required value.')
609
Miss Islington (bot)2b675f02020-01-29 06:41:49 -0800610 mtime_ns = os.stat(TESTFN).st_mtime_ns
611 if mtime_ns != (4386268800 * 10**9):
612 # XFS filesystem is limited to 32-bit timestamp, but the syscall
613 # didn't fail. Moreover, there is a VFS bug which returns
614 # a cached timestamp which is different than the value on disk.
615 #
616 # Test st_mtime_ns rather than st_mtime to avoid rounding issues.
617 #
618 # https://bugzilla.redhat.com/show_bug.cgi?id=1795576
619 # https://bugs.python.org/issue39460#msg360952
620 self.skipTest(f"Linux VFS/XFS kernel bug detected: {mtime_ns=}")
621
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200622 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
623 self.assertRaises(struct.error, zipfp.write, TESTFN)
624
Marcel Plch77b112c2018-08-31 16:43:31 +0200625 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
626 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200627 zinfo = zipfp.getinfo(TESTFN)
628 self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
629
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200630
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300631@requires_zlib
632class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,
633 unittest.TestCase):
634 compression = zipfile.ZIP_DEFLATED
635
Ezio Melottiafd0d112009-07-15 17:17:17 +0000636 def test_per_file_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000637 """Check that files within a Zip archive can have different
638 compression options."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000639 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
640 zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
641 zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
642 sinfo = zipfp.getinfo('storeme')
643 dinfo = zipfp.getinfo('deflateme')
644 self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
645 self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000646
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300647@requires_bz2
648class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile,
649 unittest.TestCase):
650 compression = zipfile.ZIP_BZIP2
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000651
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300652@requires_lzma
653class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile,
654 unittest.TestCase):
655 compression = zipfile.ZIP_LZMA
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000656
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300657
658class AbstractTestZip64InSmallFiles:
659 # These tests test the ZIP64 functionality without using large files,
660 # see test_zipfile64 for proper tests.
661
662 @classmethod
663 def setUpClass(cls):
664 line_gen = (bytes("Test of zipfile line %d." % i, "ascii")
665 for i in range(0, FIXEDTEST_SIZE))
666 cls.data = b'\n'.join(line_gen)
667
668 def setUp(self):
669 self._limit = zipfile.ZIP64_LIMIT
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300670 self._filecount_limit = zipfile.ZIP_FILECOUNT_LIMIT
671 zipfile.ZIP64_LIMIT = 1000
672 zipfile.ZIP_FILECOUNT_LIMIT = 9
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300673
674 # Make a source file with some lines
675 with open(TESTFN, "wb") as fp:
676 fp.write(self.data)
677
678 def zip_test(self, f, compression):
679 # Create the ZIP archive
680 with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
681 zipfp.write(TESTFN, "another.name")
682 zipfp.write(TESTFN, TESTFN)
683 zipfp.writestr("strfile", self.data)
684
685 # Read the ZIP archive
686 with zipfile.ZipFile(f, "r", compression) as zipfp:
687 self.assertEqual(zipfp.read(TESTFN), self.data)
688 self.assertEqual(zipfp.read("another.name"), self.data)
689 self.assertEqual(zipfp.read("strfile"), self.data)
690
691 # Print the ZIP directory
692 fp = io.StringIO()
693 zipfp.printdir(fp)
694
695 directory = fp.getvalue()
696 lines = directory.splitlines()
697 self.assertEqual(len(lines), 4) # Number of files + header
698
699 self.assertIn('File Name', lines[0])
700 self.assertIn('Modified', lines[0])
701 self.assertIn('Size', lines[0])
702
703 fn, date, time_, size = lines[1].split()
704 self.assertEqual(fn, 'another.name')
705 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
706 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
707 self.assertEqual(size, str(len(self.data)))
708
709 # Check the namelist
710 names = zipfp.namelist()
711 self.assertEqual(len(names), 3)
712 self.assertIn(TESTFN, names)
713 self.assertIn("another.name", names)
714 self.assertIn("strfile", names)
715
716 # Check infolist
717 infos = zipfp.infolist()
718 names = [i.filename for i in infos]
719 self.assertEqual(len(names), 3)
720 self.assertIn(TESTFN, names)
721 self.assertIn("another.name", names)
722 self.assertIn("strfile", names)
723 for i in infos:
724 self.assertEqual(i.file_size, len(self.data))
725
726 # check getinfo
727 for nm in (TESTFN, "another.name", "strfile"):
728 info = zipfp.getinfo(nm)
729 self.assertEqual(info.filename, nm)
730 self.assertEqual(info.file_size, len(self.data))
731
732 # Check that testzip doesn't raise an exception
733 zipfp.testzip()
734
735 def test_basic(self):
736 for f in get_files(self):
737 self.zip_test(f, self.compression)
738
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300739 def test_too_many_files(self):
740 # This test checks that more than 64k files can be added to an archive,
741 # and that the resulting archive can be read properly by ZipFile
742 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
743 allowZip64=True)
744 zipf.debug = 100
745 numfiles = 15
746 for i in range(numfiles):
747 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
748 self.assertEqual(len(zipf.namelist()), numfiles)
749 zipf.close()
750
751 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
752 self.assertEqual(len(zipf2.namelist()), numfiles)
753 for i in range(numfiles):
754 content = zipf2.read("foo%08d" % i).decode('ascii')
755 self.assertEqual(content, "%d" % (i**3 % 57))
756 zipf2.close()
757
758 def test_too_many_files_append(self):
759 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
760 allowZip64=False)
761 zipf.debug = 100
762 numfiles = 9
763 for i in range(numfiles):
764 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
765 self.assertEqual(len(zipf.namelist()), numfiles)
766 with self.assertRaises(zipfile.LargeZipFile):
767 zipf.writestr("foo%08d" % numfiles, b'')
768 self.assertEqual(len(zipf.namelist()), numfiles)
769 zipf.close()
770
771 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
772 allowZip64=False)
773 zipf.debug = 100
774 self.assertEqual(len(zipf.namelist()), numfiles)
775 with self.assertRaises(zipfile.LargeZipFile):
776 zipf.writestr("foo%08d" % numfiles, b'')
777 self.assertEqual(len(zipf.namelist()), numfiles)
778 zipf.close()
779
780 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
781 allowZip64=True)
782 zipf.debug = 100
783 self.assertEqual(len(zipf.namelist()), numfiles)
784 numfiles2 = 15
785 for i in range(numfiles, numfiles2):
786 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
787 self.assertEqual(len(zipf.namelist()), numfiles2)
788 zipf.close()
789
790 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
791 self.assertEqual(len(zipf2.namelist()), numfiles2)
792 for i in range(numfiles2):
793 content = zipf2.read("foo%08d" % i).decode('ascii')
794 self.assertEqual(content, "%d" % (i**3 % 57))
795 zipf2.close()
796
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300797 def tearDown(self):
798 zipfile.ZIP64_LIMIT = self._limit
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300799 zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300800 unlink(TESTFN)
801 unlink(TESTFN2)
802
803
804class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
805 unittest.TestCase):
806 compression = zipfile.ZIP_STORED
807
808 def large_file_exception_test(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200809 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300810 self.assertRaises(zipfile.LargeZipFile,
811 zipfp.write, TESTFN, "another.name")
812
813 def large_file_exception_test2(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200814 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300815 self.assertRaises(zipfile.LargeZipFile,
816 zipfp.writestr, "another.name", self.data)
817
818 def test_large_file_exception(self):
819 for f in get_files(self):
820 self.large_file_exception_test(f, zipfile.ZIP_STORED)
821 self.large_file_exception_test2(f, zipfile.ZIP_STORED)
822
823 def test_absolute_arcnames(self):
824 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
825 allowZip64=True) as zipfp:
826 zipfp.write(TESTFN, "/absolute")
827
828 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
829 self.assertEqual(zipfp.namelist(), ["absolute"])
830
Serhiy Storchaka9bdb7be2018-09-17 15:36:40 +0300831 def test_append(self):
832 # Test that appending to the Zip64 archive doesn't change
833 # extra fields of existing entries.
834 with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp:
835 zipfp.writestr("strfile", self.data)
836 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
837 zinfo = zipfp.getinfo("strfile")
838 extra = zinfo.extra
839 with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp:
840 zipfp.writestr("strfile2", self.data)
841 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
842 zinfo = zipfp.getinfo("strfile")
843 self.assertEqual(zinfo.extra, extra)
844
Miss Skeleton (bot)3801b262019-10-29 00:44:07 -0700845 def make_zip64_file(
846 self, file_size_64_set=False, file_size_extra=False,
847 compress_size_64_set=False, compress_size_extra=False,
848 header_offset_64_set=False, header_offset_extra=False,
849 ):
850 """Generate bytes sequence for a zip with (incomplete) zip64 data.
851
852 The actual values (not the zip 64 0xffffffff values) stored in the file
853 are:
854 file_size: 8
855 compress_size: 8
856 header_offset: 0
857 """
858 actual_size = 8
859 actual_header_offset = 0
860 local_zip64_fields = []
861 central_zip64_fields = []
862
863 file_size = actual_size
864 if file_size_64_set:
865 file_size = 0xffffffff
866 if file_size_extra:
867 local_zip64_fields.append(actual_size)
868 central_zip64_fields.append(actual_size)
869 file_size = struct.pack("<L", file_size)
870
871 compress_size = actual_size
872 if compress_size_64_set:
873 compress_size = 0xffffffff
874 if compress_size_extra:
875 local_zip64_fields.append(actual_size)
876 central_zip64_fields.append(actual_size)
877 compress_size = struct.pack("<L", compress_size)
878
879 header_offset = actual_header_offset
880 if header_offset_64_set:
881 header_offset = 0xffffffff
882 if header_offset_extra:
883 central_zip64_fields.append(actual_header_offset)
884 header_offset = struct.pack("<L", header_offset)
885
886 local_extra = struct.pack(
887 '<HH' + 'Q'*len(local_zip64_fields),
888 0x0001,
889 8*len(local_zip64_fields),
890 *local_zip64_fields
891 )
892
893 central_extra = struct.pack(
894 '<HH' + 'Q'*len(central_zip64_fields),
895 0x0001,
896 8*len(central_zip64_fields),
897 *central_zip64_fields
898 )
899
900 central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
901 offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
902
903 local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
904 central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
905
906 filename = b"test.txt"
907 content = b"test1234"
908 filename_length = struct.pack("<H", len(filename))
909 zip64_contents = (
910 # Local file header
911 b"PK\x03\x04\x14\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
912 + compress_size
913 + file_size
914 + filename_length
915 + local_extra_length
916 + filename
917 + local_extra
918 + content
919 # Central directory:
920 + b"PK\x01\x02-\x03-\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
921 + compress_size
922 + file_size
923 + filename_length
924 + central_extra_length
925 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01"
926 + header_offset
927 + filename
928 + central_extra
929 # Zip64 end of central directory
930 + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
931 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
932 + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
933 + central_dir_size
934 + offset_to_central_dir
935 # Zip64 end of central directory locator
936 + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
937 + b"\x00\x00\x00"
938 # end of central directory
939 + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
940 + b"\x00\x00\x00\x00"
941 )
942 return zip64_contents
943
944 def test_bad_zip64_extra(self):
945 """Missing zip64 extra records raises an exception.
946
947 There are 4 fields that the zip64 format handles (the disk number is
948 not used in this module and so is ignored here). According to the zip
949 spec:
950 The order of the fields in the zip64 extended
951 information record is fixed, but the fields MUST
952 only appear if the corresponding Local or Central
953 directory record field is set to 0xFFFF or 0xFFFFFFFF.
954
955 If the zip64 extra content doesn't contain enough entries for the
956 number of fields marked with 0xFFFF or 0xFFFFFFFF, we raise an error.
957 This test mismatches the length of the zip64 extra field and the number
958 of fields set to indicate the presence of zip64 data.
959 """
960 # zip64 file size present, no fields in extra, expecting one, equals
961 # missing file size.
962 missing_file_size_extra = self.make_zip64_file(
963 file_size_64_set=True,
964 )
965 with self.assertRaises(zipfile.BadZipFile) as e:
966 zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
967 self.assertIn('file size', str(e.exception).lower())
968
969 # zip64 file size present, zip64 compress size present, one field in
970 # extra, expecting two, equals missing compress size.
971 missing_compress_size_extra = self.make_zip64_file(
972 file_size_64_set=True,
973 file_size_extra=True,
974 compress_size_64_set=True,
975 )
976 with self.assertRaises(zipfile.BadZipFile) as e:
977 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
978 self.assertIn('compress size', str(e.exception).lower())
979
980 # zip64 compress size present, no fields in extra, expecting one,
981 # equals missing compress size.
982 missing_compress_size_extra = self.make_zip64_file(
983 compress_size_64_set=True,
984 )
985 with self.assertRaises(zipfile.BadZipFile) as e:
986 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
987 self.assertIn('compress size', str(e.exception).lower())
988
989 # zip64 file size present, zip64 compress size present, zip64 header
990 # offset present, two fields in extra, expecting three, equals missing
991 # header offset
992 missing_header_offset_extra = self.make_zip64_file(
993 file_size_64_set=True,
994 file_size_extra=True,
995 compress_size_64_set=True,
996 compress_size_extra=True,
997 header_offset_64_set=True,
998 )
999 with self.assertRaises(zipfile.BadZipFile) as e:
1000 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1001 self.assertIn('header offset', str(e.exception).lower())
1002
1003 # zip64 compress size present, zip64 header offset present, one field
1004 # in extra, expecting two, equals missing header offset
1005 missing_header_offset_extra = self.make_zip64_file(
1006 file_size_64_set=False,
1007 compress_size_64_set=True,
1008 compress_size_extra=True,
1009 header_offset_64_set=True,
1010 )
1011 with self.assertRaises(zipfile.BadZipFile) as e:
1012 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1013 self.assertIn('header offset', str(e.exception).lower())
1014
1015 # zip64 file size present, zip64 header offset present, one field in
1016 # extra, expecting two, equals missing header offset
1017 missing_header_offset_extra = self.make_zip64_file(
1018 file_size_64_set=True,
1019 file_size_extra=True,
1020 compress_size_64_set=False,
1021 header_offset_64_set=True,
1022 )
1023 with self.assertRaises(zipfile.BadZipFile) as e:
1024 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1025 self.assertIn('header offset', str(e.exception).lower())
1026
1027 # zip64 header offset present, no fields in extra, expecting one,
1028 # equals missing header offset
1029 missing_header_offset_extra = self.make_zip64_file(
1030 file_size_64_set=False,
1031 compress_size_64_set=False,
1032 header_offset_64_set=True,
1033 )
1034 with self.assertRaises(zipfile.BadZipFile) as e:
1035 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1036 self.assertIn('header offset', str(e.exception).lower())
1037
1038 def test_generated_valid_zip64_extra(self):
1039 # These values are what is set in the make_zip64_file method.
1040 expected_file_size = 8
1041 expected_compress_size = 8
1042 expected_header_offset = 0
1043 expected_content = b"test1234"
1044
1045 # Loop through the various valid combinations of zip64 masks
1046 # present and extra fields present.
1047 params = (
1048 {"file_size_64_set": True, "file_size_extra": True},
1049 {"compress_size_64_set": True, "compress_size_extra": True},
1050 {"header_offset_64_set": True, "header_offset_extra": True},
1051 )
1052
1053 for r in range(1, len(params) + 1):
1054 for combo in itertools.combinations(params, r):
1055 kwargs = {}
1056 for c in combo:
1057 kwargs.update(c)
1058 with zipfile.ZipFile(io.BytesIO(self.make_zip64_file(**kwargs))) as zf:
1059 zinfo = zf.infolist()[0]
1060 self.assertEqual(zinfo.file_size, expected_file_size)
1061 self.assertEqual(zinfo.compress_size, expected_compress_size)
1062 self.assertEqual(zinfo.header_offset, expected_header_offset)
1063 self.assertEqual(zf.read(zinfo), expected_content)
1064
1065
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001066@requires_zlib
1067class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1068 unittest.TestCase):
1069 compression = zipfile.ZIP_DEFLATED
1070
1071@requires_bz2
1072class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1073 unittest.TestCase):
1074 compression = zipfile.ZIP_BZIP2
1075
1076@requires_lzma
1077class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1078 unittest.TestCase):
1079 compression = zipfile.ZIP_LZMA
1080
1081
Serhiy Storchaka4c0d9ea2017-04-12 16:03:23 +03001082class AbstractWriterTests:
1083
1084 def tearDown(self):
1085 unlink(TESTFN2)
1086
1087 def test_close_after_close(self):
1088 data = b'content'
1089 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1090 w = zipf.open('test', 'w')
1091 w.write(data)
1092 w.close()
1093 self.assertTrue(w.closed)
1094 w.close()
1095 self.assertTrue(w.closed)
1096 self.assertEqual(zipf.read('test'), data)
1097
1098 def test_write_after_close(self):
1099 data = b'content'
1100 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1101 w = zipf.open('test', 'w')
1102 w.write(data)
1103 w.close()
1104 self.assertTrue(w.closed)
1105 self.assertRaises(ValueError, w.write, b'')
1106 self.assertEqual(zipf.read('test'), data)
1107
1108class StoredWriterTests(AbstractWriterTests, unittest.TestCase):
1109 compression = zipfile.ZIP_STORED
1110
1111@requires_zlib
1112class DeflateWriterTests(AbstractWriterTests, unittest.TestCase):
1113 compression = zipfile.ZIP_DEFLATED
1114
1115@requires_bz2
1116class Bzip2WriterTests(AbstractWriterTests, unittest.TestCase):
1117 compression = zipfile.ZIP_BZIP2
1118
1119@requires_lzma
1120class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
1121 compression = zipfile.ZIP_LZMA
1122
1123
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001124class PyZipFileTests(unittest.TestCase):
1125 def assertCompiledIn(self, name, namelist):
1126 if name + 'o' not in namelist:
1127 self.assertIn(name + 'c', namelist)
1128
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001129 def requiresWriteAccess(self, path):
Berker Peksage1efc072015-02-16 04:36:18 +02001130 # effective_ids unavailable on windows
1131 if not os.access(path, os.W_OK,
1132 effective_ids=os.access in os.supports_effective_ids):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001133 self.skipTest('requires write access to the installed location')
Serhiy Storchakad86a6ef2015-09-19 10:55:20 +03001134 filename = os.path.join(path, 'test_zipfile.try')
1135 try:
1136 fd = os.open(filename, os.O_WRONLY | os.O_CREAT)
1137 os.close(fd)
1138 except Exception:
1139 self.skipTest('requires write access to the installed location')
1140 unlink(filename)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001141
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001142 def test_write_pyfile(self):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001143 self.requiresWriteAccess(os.path.dirname(__file__))
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001144 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 path_split = fn.split(os.sep)
1148 if os.altsep is not None:
1149 path_split.extend(fn.split(os.altsep))
1150 if '__pycache__' in path_split:
Serhiy Storchaka9068e4d2013-07-22 21:02:14 +03001151 fn = importlib.util.source_from_cache(fn)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001152 else:
1153 fn = fn[:-1]
1154
1155 zipfp.writepy(fn)
1156
1157 bn = os.path.basename(fn)
1158 self.assertNotIn(bn, zipfp.namelist())
1159 self.assertCompiledIn(bn, zipfp.namelist())
1160
1161 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1162 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001163 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001164 fn = fn[:-1]
1165
1166 zipfp.writepy(fn, "testpackage")
1167
1168 bn = "%s/%s" % ("testpackage", os.path.basename(fn))
1169 self.assertNotIn(bn, zipfp.namelist())
1170 self.assertCompiledIn(bn, zipfp.namelist())
1171
1172 def test_write_python_package(self):
1173 import email
1174 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001175 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001176
1177 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1178 zipfp.writepy(packagedir)
1179
1180 # Check for a couple of modules at different levels of the
1181 # hierarchy
1182 names = zipfp.namelist()
1183 self.assertCompiledIn('email/__init__.py', names)
1184 self.assertCompiledIn('email/mime/text.py', names)
1185
Christian Tismer59202e52013-10-21 03:59:23 +02001186 def test_write_filtered_python_package(self):
1187 import test
1188 packagedir = os.path.dirname(test.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001189 self.requiresWriteAccess(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001190
1191 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1192
Christian Tismer59202e52013-10-21 03:59:23 +02001193 # first make sure that the test folder gives error messages
Georg Brandla6065422013-10-21 08:29:29 +02001194 # (on the badsyntax_... files)
1195 with captured_stdout() as reportSIO:
1196 zipfp.writepy(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001197 reportStr = reportSIO.getvalue()
1198 self.assertTrue('SyntaxError' in reportStr)
1199
Christian Tismer410d9312013-10-22 04:09:28 +02001200 # then check that the filter works on the whole package
Georg Brandla6065422013-10-21 08:29:29 +02001201 with captured_stdout() as reportSIO:
1202 zipfp.writepy(packagedir, filterfunc=lambda whatever: False)
Christian Tismer59202e52013-10-21 03:59:23 +02001203 reportStr = reportSIO.getvalue()
1204 self.assertTrue('SyntaxError' not in reportStr)
1205
Christian Tismer410d9312013-10-22 04:09:28 +02001206 # then check that the filter works on individual files
Larry Hastings7e63b362015-05-08 06:54:58 -07001207 def filter(path):
1208 return not os.path.basename(path).startswith("bad")
Serhiy Storchakac46d1fa2014-01-20 21:59:33 +02001209 with captured_stdout() as reportSIO, self.assertWarns(UserWarning):
Larry Hastings7e63b362015-05-08 06:54:58 -07001210 zipfp.writepy(packagedir, filterfunc=filter)
Christian Tismer410d9312013-10-22 04:09:28 +02001211 reportStr = reportSIO.getvalue()
1212 if reportStr:
1213 print(reportStr)
1214 self.assertTrue('SyntaxError' not in reportStr)
1215
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001216 def test_write_with_optimization(self):
1217 import email
1218 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001219 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001220 optlevel = 1 if __debug__ else 0
Brett Cannonf299abd2015-04-13 14:21:02 -04001221 ext = '.pyc'
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001222
1223 with TemporaryFile() as t, \
Christian Tismer59202e52013-10-21 03:59:23 +02001224 zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001225 zipfp.writepy(packagedir)
1226
1227 names = zipfp.namelist()
1228 self.assertIn('email/__init__' + ext, names)
1229 self.assertIn('email/mime/text' + ext, names)
1230
1231 def test_write_python_directory(self):
1232 os.mkdir(TESTFN2)
1233 try:
1234 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1235 fp.write("print(42)\n")
1236
1237 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1238 fp.write("print(42 * 42)\n")
1239
1240 with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp:
1241 fp.write("bla bla bla\n")
1242
1243 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1244 zipfp.writepy(TESTFN2)
1245
1246 names = zipfp.namelist()
1247 self.assertCompiledIn('mod1.py', names)
1248 self.assertCompiledIn('mod2.py', names)
1249 self.assertNotIn('mod2.txt', names)
1250
1251 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001252 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001253
Christian Tismer410d9312013-10-22 04:09:28 +02001254 def test_write_python_directory_filtered(self):
1255 os.mkdir(TESTFN2)
1256 try:
1257 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1258 fp.write("print(42)\n")
1259
1260 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1261 fp.write("print(42 * 42)\n")
1262
1263 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1264 zipfp.writepy(TESTFN2, filterfunc=lambda fn:
1265 not fn.endswith('mod2.py'))
1266
1267 names = zipfp.namelist()
1268 self.assertCompiledIn('mod1.py', names)
1269 self.assertNotIn('mod2.py', names)
1270
1271 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001272 rmtree(TESTFN2)
Christian Tismer410d9312013-10-22 04:09:28 +02001273
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001274 def test_write_non_pyfile(self):
1275 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1276 with open(TESTFN, 'w') as f:
1277 f.write('most definitely not a python file')
1278 self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
Victor Stinner88b215e2014-09-04 00:51:09 +02001279 unlink(TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001280
1281 def test_write_pyfile_bad_syntax(self):
1282 os.mkdir(TESTFN2)
1283 try:
1284 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1285 fp.write("Bad syntax in python file\n")
1286
1287 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1288 # syntax errors are printed to stdout
1289 with captured_stdout() as s:
1290 zipfp.writepy(os.path.join(TESTFN2, "mod1.py"))
1291
1292 self.assertIn("SyntaxError", s.getvalue())
1293
1294 # as it will not have compiled the python file, it will
Brett Cannonf299abd2015-04-13 14:21:02 -04001295 # include the .py file not .pyc
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001296 names = zipfp.namelist()
1297 self.assertIn('mod1.py', names)
1298 self.assertNotIn('mod1.pyc', names)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001299
1300 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001301 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001302
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001303 def test_write_pathlike(self):
1304 os.mkdir(TESTFN2)
1305 try:
1306 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1307 fp.write("print(42)\n")
1308
1309 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1310 zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py")
1311 names = zipfp.namelist()
1312 self.assertCompiledIn('mod1.py', names)
1313 finally:
1314 rmtree(TESTFN2)
1315
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001316
1317class ExtractTests(unittest.TestCase):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001318
1319 def make_test_file(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001320 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1321 for fpath, fdata in SMALL_TEST_DATA:
1322 zipfp.writestr(fpath, fdata)
Christian Heimes790c8232008-01-07 21:14:23 +00001323
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001324 def test_extract(self):
1325 with temp_cwd():
1326 self.make_test_file()
1327 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1328 for fpath, fdata in SMALL_TEST_DATA:
1329 writtenfile = zipfp.extract(fpath)
1330
1331 # make sure it was written to the right place
1332 correctfile = os.path.join(os.getcwd(), fpath)
1333 correctfile = os.path.normpath(correctfile)
1334
1335 self.assertEqual(writtenfile, correctfile)
1336
1337 # make sure correct data is in correct file
1338 with open(writtenfile, "rb") as f:
1339 self.assertEqual(fdata.encode(), f.read())
1340
1341 unlink(writtenfile)
1342
1343 def _test_extract_with_target(self, target):
1344 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001345 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1346 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001347 writtenfile = zipfp.extract(fpath, target)
Christian Heimes790c8232008-01-07 21:14:23 +00001348
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001349 # make sure it was written to the right place
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001350 correctfile = os.path.join(target, fpath)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001351 correctfile = os.path.normpath(correctfile)
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001352 self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target))
Christian Heimes790c8232008-01-07 21:14:23 +00001353
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001354 # make sure correct data is in correct file
Brian Curtin8fb9b862010-11-18 02:15:28 +00001355 with open(writtenfile, "rb") as f:
1356 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001357
Victor Stinner88b215e2014-09-04 00:51:09 +02001358 unlink(writtenfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001359
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001360 unlink(TESTFN2)
1361
1362 def test_extract_with_target(self):
1363 with temp_dir() as extdir:
1364 self._test_extract_with_target(extdir)
1365
1366 def test_extract_with_target_pathlike(self):
1367 with temp_dir() as extdir:
1368 self._test_extract_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001369
Ezio Melottiafd0d112009-07-15 17:17:17 +00001370 def test_extract_all(self):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001371 with temp_cwd():
1372 self.make_test_file()
1373 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1374 zipfp.extractall()
1375 for fpath, fdata in SMALL_TEST_DATA:
1376 outfile = os.path.join(os.getcwd(), fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001377
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001378 with open(outfile, "rb") as f:
1379 self.assertEqual(fdata.encode(), f.read())
1380
1381 unlink(outfile)
1382
1383 def _test_extract_all_with_target(self, target):
1384 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001385 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001386 zipfp.extractall(target)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001387 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001388 outfile = os.path.join(target, fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001389
Brian Curtin8fb9b862010-11-18 02:15:28 +00001390 with open(outfile, "rb") as f:
1391 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001392
Victor Stinner88b215e2014-09-04 00:51:09 +02001393 unlink(outfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001394
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001395 unlink(TESTFN2)
1396
1397 def test_extract_all_with_target(self):
1398 with temp_dir() as extdir:
1399 self._test_extract_all_with_target(extdir)
1400
1401 def test_extract_all_with_target_pathlike(self):
1402 with temp_dir() as extdir:
1403 self._test_extract_all_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001404
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001405 def check_file(self, filename, content):
1406 self.assertTrue(os.path.isfile(filename))
1407 with open(filename, 'rb') as f:
1408 self.assertEqual(f.read(), content)
1409
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001410 def test_sanitize_windows_name(self):
1411 san = zipfile.ZipFile._sanitize_windows_name
1412 # Passing pathsep in allows this test to work regardless of platform.
1413 self.assertEqual(san(r',,?,C:,foo,bar/z', ','), r'_,C_,foo,bar/z')
1414 self.assertEqual(san(r'a\b,c<d>e|f"g?h*i', ','), r'a\b,c_d_e_f_g_h_i')
1415 self.assertEqual(san('../../foo../../ba..r', '/'), r'foo/ba..r')
1416
1417 def test_extract_hackers_arcnames_common_cases(self):
1418 common_hacknames = [
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001419 ('../foo/bar', 'foo/bar'),
1420 ('foo/../bar', 'foo/bar'),
1421 ('foo/../../bar', 'foo/bar'),
1422 ('foo/bar/..', 'foo/bar'),
1423 ('./../foo/bar', 'foo/bar'),
1424 ('/foo/bar', 'foo/bar'),
1425 ('/foo/../bar', 'foo/bar'),
1426 ('/foo/../../bar', 'foo/bar'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001427 ]
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001428 self._test_extract_hackers_arcnames(common_hacknames)
1429
1430 @unittest.skipIf(os.path.sep != '\\', 'Requires \\ as path separator.')
1431 def test_extract_hackers_arcnames_windows_only(self):
1432 """Test combination of path fixing and windows name sanitization."""
1433 windows_hacknames = [
Christian Tismer59202e52013-10-21 03:59:23 +02001434 (r'..\foo\bar', 'foo/bar'),
1435 (r'..\/foo\/bar', 'foo/bar'),
1436 (r'foo/\..\/bar', 'foo/bar'),
1437 (r'foo\/../\bar', 'foo/bar'),
1438 (r'C:foo/bar', 'foo/bar'),
1439 (r'C:/foo/bar', 'foo/bar'),
1440 (r'C://foo/bar', 'foo/bar'),
1441 (r'C:\foo\bar', 'foo/bar'),
1442 (r'//conky/mountpoint/foo/bar', 'foo/bar'),
1443 (r'\\conky\mountpoint\foo\bar', 'foo/bar'),
1444 (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1445 (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1446 (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1447 (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1448 (r'//?/C:/foo/bar', 'foo/bar'),
1449 (r'\\?\C:\foo\bar', 'foo/bar'),
1450 (r'C:/../C:/foo/bar', 'C_/foo/bar'),
1451 (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
1452 ('../../foo../../ba..r', 'foo/ba..r'),
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001453 ]
1454 self._test_extract_hackers_arcnames(windows_hacknames)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001455
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001456 @unittest.skipIf(os.path.sep != '/', r'Requires / as path separator.')
1457 def test_extract_hackers_arcnames_posix_only(self):
1458 posix_hacknames = [
1459 ('//foo/bar', 'foo/bar'),
1460 ('../../foo../../ba..r', 'foo../ba..r'),
1461 (r'foo/..\bar', r'foo/..\bar'),
1462 ]
1463 self._test_extract_hackers_arcnames(posix_hacknames)
1464
1465 def _test_extract_hackers_arcnames(self, hacknames):
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001466 for arcname, fixedname in hacknames:
1467 content = b'foobar' + arcname.encode()
1468 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001469 zinfo = zipfile.ZipInfo()
1470 # preserve backslashes
1471 zinfo.filename = arcname
1472 zinfo.external_attr = 0o600 << 16
1473 zipfp.writestr(zinfo, content)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001474
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001475 arcname = arcname.replace(os.sep, "/")
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001476 targetpath = os.path.join('target', 'subdir', 'subsub')
1477 correctfile = os.path.join(targetpath, *fixedname.split('/'))
1478
1479 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1480 writtenfile = zipfp.extract(arcname, targetpath)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001481 self.assertEqual(writtenfile, correctfile,
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001482 msg='extract %r: %r != %r' %
1483 (arcname, writtenfile, correctfile))
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001484 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001485 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001486
1487 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1488 zipfp.extractall(targetpath)
1489 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001490 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001491
1492 correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
1493
1494 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1495 writtenfile = zipfp.extract(arcname)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001496 self.assertEqual(writtenfile, correctfile,
1497 msg="extract %r" % arcname)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001498 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001499 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001500
1501 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1502 zipfp.extractall()
1503 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001504 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001505
Victor Stinner88b215e2014-09-04 00:51:09 +02001506 unlink(TESTFN2)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001507
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001508
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001509class OtherTests(unittest.TestCase):
1510 def test_open_via_zip_info(self):
1511 # Create the ZIP archive
1512 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1513 zipfp.writestr("name", "foo")
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001514 with self.assertWarns(UserWarning):
1515 zipfp.writestr("name", "bar")
1516 self.assertEqual(zipfp.namelist(), ["name"] * 2)
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001517
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001518 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1519 infos = zipfp.infolist()
1520 data = b""
1521 for info in infos:
1522 with zipfp.open(info) as zipopen:
1523 data += zipopen.read()
1524 self.assertIn(data, {b"foobar", b"barfoo"})
1525 data = b""
1526 for info in infos:
1527 data += zipfp.read(info)
1528 self.assertIn(data, {b"foobar", b"barfoo"})
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02001529
Gregory P. Smithb0d9ca922009-07-07 05:06:04 +00001530 def test_writestr_extended_local_header_issue1202(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001531 with zipfile.ZipFile(TESTFN2, 'w') as orig_zip:
1532 for data in 'abcdefghijklmnop':
1533 zinfo = zipfile.ZipInfo(data)
1534 zinfo.flag_bits |= 0x08 # Include an extended local header.
1535 orig_zip.writestr(zinfo, data)
1536
1537 def test_close(self):
1538 """Check that the zipfile is closed after the 'with' block."""
1539 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1540 for fpath, fdata in SMALL_TEST_DATA:
1541 zipfp.writestr(fpath, fdata)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001542 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1543 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001544
1545 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001546 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1547 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001548
1549 def test_close_on_exception(self):
1550 """Check that the zipfile is closed if an exception is raised in the
1551 'with' block."""
1552 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1553 for fpath, fdata in SMALL_TEST_DATA:
1554 zipfp.writestr(fpath, fdata)
1555
1556 try:
1557 with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
Georg Brandl4d540882010-10-28 06:42:33 +00001558 raise zipfile.BadZipFile()
1559 except zipfile.BadZipFile:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001560 self.assertIsNone(zipfp2.fp, 'zipfp is not closed')
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00001561
Martin v. Löwisd099b562012-05-01 14:08:22 +02001562 def test_unsupported_version(self):
1563 # File has an extract_version of 120
1564 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 +02001565 b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00xPK\x01\x02x\x03x\x00\x00\x00\x00'
1566 b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
1567 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06'
1568 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 +03001569
Martin v. Löwisd099b562012-05-01 14:08:22 +02001570 self.assertRaises(NotImplementedError, zipfile.ZipFile,
1571 io.BytesIO(data), 'r')
1572
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001573 @requires_zlib
1574 def test_read_unicode_filenames(self):
1575 # bug #10801
1576 fname = findfile('zip_cp437_header.zip')
1577 with zipfile.ZipFile(fname) as zipfp:
1578 for name in zipfp.namelist():
1579 zipfp.open(name).close()
1580
1581 def test_write_unicode_filenames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001582 with zipfile.ZipFile(TESTFN, "w") as zf:
1583 zf.writestr("foo.txt", "Test for unicode filename")
1584 zf.writestr("\xf6.txt", "Test for unicode filename")
Ezio Melottie9615932010-01-24 19:26:24 +00001585 self.assertIsInstance(zf.infolist()[0].filename, str)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001586
1587 with zipfile.ZipFile(TESTFN, "r") as zf:
1588 self.assertEqual(zf.filelist[0].filename, "foo.txt")
1589 self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
Martin v. Löwis8570f6a2008-05-05 17:44:38 +00001590
Serhiy Storchaka764fc9b2015-03-25 10:09:41 +02001591 def test_exclusive_create_zip_file(self):
1592 """Test exclusive creating a new zipfile."""
1593 unlink(TESTFN2)
1594 filename = 'testfile.txt'
1595 content = b'hello, world. this is some content.'
1596 with zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED) as zipfp:
1597 zipfp.writestr(filename, content)
1598 with self.assertRaises(FileExistsError):
1599 zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED)
1600 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1601 self.assertEqual(zipfp.namelist(), [filename])
1602 self.assertEqual(zipfp.read(filename), content)
1603
Ezio Melottiafd0d112009-07-15 17:17:17 +00001604 def test_create_non_existent_file_for_append(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00001605 if os.path.exists(TESTFN):
1606 os.unlink(TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001607
Thomas Wouterscf297e42007-02-23 15:07:44 +00001608 filename = 'testfile.txt'
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001609 content = b'hello, world. this is some content.'
Guido van Rossumd8faa362007-04-27 19:54:29 +00001610
Thomas Wouterscf297e42007-02-23 15:07:44 +00001611 try:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001612 with zipfile.ZipFile(TESTFN, 'a') as zf:
1613 zf.writestr(filename, content)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001614 except OSError:
Thomas Wouterscf297e42007-02-23 15:07:44 +00001615 self.fail('Could not append data to a non-existent zip file.')
1616
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001617 self.assertTrue(os.path.exists(TESTFN))
Thomas Wouterscf297e42007-02-23 15:07:44 +00001618
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001619 with zipfile.ZipFile(TESTFN, 'r') as zf:
1620 self.assertEqual(zf.read(filename), content)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001621
Ezio Melottiafd0d112009-07-15 17:17:17 +00001622 def test_close_erroneous_file(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001623 # This test checks that the ZipFile constructor closes the file object
Ezio Melotti35386712009-12-31 13:22:41 +00001624 # it opens if there's an error in the file. If it doesn't, the
1625 # traceback holds a reference to the ZipFile object and, indirectly,
1626 # the file object.
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001627 # On Windows, this causes the os.unlink() call to fail because the
1628 # underlying file is still open. This is SF bug #412214.
1629 #
Ezio Melotti35386712009-12-31 13:22:41 +00001630 with open(TESTFN, "w") as fp:
1631 fp.write("this is not a legal zip file\n")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001632 try:
1633 zf = zipfile.ZipFile(TESTFN)
Georg Brandl4d540882010-10-28 06:42:33 +00001634 except zipfile.BadZipFile:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001635 pass
1636
Ezio Melottiafd0d112009-07-15 17:17:17 +00001637 def test_is_zip_erroneous_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001638 """Check that is_zipfile() correctly identifies non-zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001639 # - passing a filename
1640 with open(TESTFN, "w") as fp:
1641 fp.write("this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001642 self.assertFalse(zipfile.is_zipfile(TESTFN))
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001643 # - passing a path-like object
1644 self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN)))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001645 # - passing a file object
1646 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001647 self.assertFalse(zipfile.is_zipfile(fp))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001648 # - passing a file-like object
1649 fp = io.BytesIO()
1650 fp.write(b"this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001651 self.assertFalse(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001652 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001653 self.assertFalse(zipfile.is_zipfile(fp))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001654
Serhiy Storchakad2b15272013-01-31 15:27:07 +02001655 def test_damaged_zipfile(self):
1656 """Check that zipfiles with missing bytes at the end raise BadZipFile."""
1657 # - Create a valid zip file
1658 fp = io.BytesIO()
1659 with zipfile.ZipFile(fp, mode="w") as zipf:
1660 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1661 zipfiledata = fp.getvalue()
1662
1663 # - Now create copies of it missing the last N bytes and make sure
1664 # a BadZipFile exception is raised when we try to open it
1665 for N in range(len(zipfiledata)):
1666 fp = io.BytesIO(zipfiledata[:N])
1667 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, fp)
1668
Ezio Melottiafd0d112009-07-15 17:17:17 +00001669 def test_is_zip_valid_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001670 """Check that is_zipfile() correctly identifies zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001671 # - passing a filename
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001672 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1673 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1674
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001675 self.assertTrue(zipfile.is_zipfile(TESTFN))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001676 # - passing a file object
1677 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001678 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001679 fp.seek(0, 0)
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001680 zip_contents = fp.read()
1681 # - passing a file-like object
1682 fp = io.BytesIO()
1683 fp.write(zip_contents)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001684 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001685 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001686 self.assertTrue(zipfile.is_zipfile(fp))
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001687
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001688 def test_non_existent_file_raises_OSError(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001689 # make sure we don't raise an AttributeError when a partially-constructed
1690 # ZipFile instance is finalized; this tests for regression on SF tracker
1691 # bug #403871.
1692
1693 # The bug we're testing for caused an AttributeError to be raised
1694 # when a ZipFile instance was created for a file that did not
1695 # exist; the .fp member was not initialized but was needed by the
1696 # __del__() method. Since the AttributeError is in the __del__(),
1697 # it is ignored, but the user should be sufficiently annoyed by
1698 # the message on the output that regression will be noticed
1699 # quickly.
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001700 self.assertRaises(OSError, zipfile.ZipFile, TESTFN)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001701
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001702 def test_empty_file_raises_BadZipFile(self):
1703 f = open(TESTFN, 'w')
1704 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001705 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001706
Ezio Melotti35386712009-12-31 13:22:41 +00001707 with open(TESTFN, 'w') as fp:
1708 fp.write("short file")
Georg Brandl4d540882010-10-28 06:42:33 +00001709 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001710
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001711 def test_closed_zip_raises_ValueError(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001712 """Verify that testzip() doesn't swallow inappropriate exceptions."""
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001713 data = io.BytesIO()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001714 with zipfile.ZipFile(data, mode="w") as zipf:
1715 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001716
Andrew Svetlov737fb892012-12-18 21:14:22 +02001717 # This is correct; calling .read on a closed ZipFile should raise
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001718 # a ValueError, and so should calling .testzip. An earlier
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001719 # version of .testzip would swallow this exception (and any other)
1720 # and report that the first file in the archive was corrupt.
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001721 self.assertRaises(ValueError, zipf.read, "foo.txt")
1722 self.assertRaises(ValueError, zipf.open, "foo.txt")
1723 self.assertRaises(ValueError, zipf.testzip)
1724 self.assertRaises(ValueError, zipf.writestr, "bogus.txt", "bogus")
Brian Curtin8fb9b862010-11-18 02:15:28 +00001725 with open(TESTFN, 'w') as f:
1726 f.write('zipfile test data')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001727 self.assertRaises(ValueError, zipf.write, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001728
Ezio Melottiafd0d112009-07-15 17:17:17 +00001729 def test_bad_constructor_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001730 """Check that bad modes passed to ZipFile constructor are caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001731 self.assertRaises(ValueError, zipfile.ZipFile, TESTFN, "q")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001732
Ezio Melottiafd0d112009-07-15 17:17:17 +00001733 def test_bad_open_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001734 """Check that bad modes passed to ZipFile.open are caught."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001735 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1736 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1737
1738 with zipfile.ZipFile(TESTFN, mode="r") as zipf:
Serhiy Storchakae670be22016-06-11 19:32:44 +03001739 # read the data to make sure the file is there
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001740 zipf.read("foo.txt")
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001741 self.assertRaises(ValueError, zipf.open, "foo.txt", "q")
Serhiy Storchakae670be22016-06-11 19:32:44 +03001742 # universal newlines support is removed
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001743 self.assertRaises(ValueError, zipf.open, "foo.txt", "U")
1744 self.assertRaises(ValueError, zipf.open, "foo.txt", "rU")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001745
Ezio Melottiafd0d112009-07-15 17:17:17 +00001746 def test_read0(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001747 """Check that calling read(0) on a ZipExtFile object returns an empty
1748 string and doesn't advance file pointer."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001749 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1750 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1751 # read the data to make sure the file is there
Brian Curtin8fb9b862010-11-18 02:15:28 +00001752 with zipf.open("foo.txt") as f:
1753 for i in range(FIXEDTEST_SIZE):
1754 self.assertEqual(f.read(0), b'')
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001755
Brian Curtin8fb9b862010-11-18 02:15:28 +00001756 self.assertEqual(f.read(), b"O, for a Muse of Fire!")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001757
Ezio Melottiafd0d112009-07-15 17:17:17 +00001758 def test_open_non_existent_item(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001759 """Check that attempting to call open() for an item that doesn't
1760 exist in the archive raises a RuntimeError."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001761 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1762 self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001763
Ezio Melottiafd0d112009-07-15 17:17:17 +00001764 def test_bad_compression_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001765 """Check that bad compression methods passed to ZipFile.open are
1766 caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001767 self.assertRaises(NotImplementedError, zipfile.ZipFile, TESTFN, "w", -1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001768
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001769 def test_unsupported_compression(self):
1770 # data is declared as shrunk, but actually deflated
1771 data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001772 b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
1773 b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
1774 b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1775 b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
1776 b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001777 with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
1778 self.assertRaises(NotImplementedError, zipf.open, 'x')
1779
Ezio Melottiafd0d112009-07-15 17:17:17 +00001780 def test_null_byte_in_filename(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001781 """Check that a filename containing a null byte is properly
1782 terminated."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001783 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1784 zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
1785 self.assertEqual(zipf.namelist(), ['foo.txt'])
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001786
Ezio Melottiafd0d112009-07-15 17:17:17 +00001787 def test_struct_sizes(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001788 """Check that ZIP internal structure sizes are calculated correctly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001789 self.assertEqual(zipfile.sizeEndCentDir, 22)
1790 self.assertEqual(zipfile.sizeCentralDir, 46)
1791 self.assertEqual(zipfile.sizeEndCentDir64, 56)
1792 self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
1793
Ezio Melottiafd0d112009-07-15 17:17:17 +00001794 def test_comments(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001795 """Check that comments on the archive are handled properly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001796
1797 # check default comment is empty
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001798 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1799 self.assertEqual(zipf.comment, b'')
1800 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1801
1802 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1803 self.assertEqual(zipfr.comment, b'')
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001804
1805 # check a simple short comment
1806 comment = b'Bravely taking to his feet, he beat a very brave retreat.'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001807 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1808 zipf.comment = comment
1809 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1810 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1811 self.assertEqual(zipf.comment, comment)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001812
1813 # check a comment of max length
1814 comment2 = ''.join(['%d' % (i**3 % 10) for i in range((1 << 16)-1)])
1815 comment2 = comment2.encode("ascii")
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001816 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1817 zipf.comment = comment2
1818 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1819
1820 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1821 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001822
1823 # check a comment that is too long is truncated
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001824 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001825 with self.assertWarns(UserWarning):
1826 zipf.comment = comment2 + b'oops'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001827 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1828 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1829 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001830
Antoine Pitrouc3991852012-06-30 17:31:37 +02001831 # check that comments are correctly modified in append mode
1832 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1833 zipf.comment = b"original comment"
1834 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1835 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1836 zipf.comment = b"an updated comment"
1837 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1838 self.assertEqual(zipf.comment, b"an updated comment")
1839
1840 # check that comments are correctly shortened in append mode
1841 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1842 zipf.comment = b"original comment that's longer"
1843 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1844 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1845 zipf.comment = b"shorter comment"
1846 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1847 self.assertEqual(zipf.comment, b"shorter comment")
1848
R David Murrayf50b38a2012-04-12 18:44:58 -04001849 def test_unicode_comment(self):
1850 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1851 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1852 with self.assertRaises(TypeError):
1853 zipf.comment = "this is an error"
1854
1855 def test_change_comment_in_empty_archive(self):
1856 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1857 self.assertFalse(zipf.filelist)
1858 zipf.comment = b"this is a comment"
1859 with zipfile.ZipFile(TESTFN, "r") as zipf:
1860 self.assertEqual(zipf.comment, b"this is a comment")
1861
1862 def test_change_comment_in_nonempty_archive(self):
1863 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1864 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1865 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1866 self.assertTrue(zipf.filelist)
1867 zipf.comment = b"this is a comment"
1868 with zipfile.ZipFile(TESTFN, "r") as zipf:
1869 self.assertEqual(zipf.comment, b"this is a comment")
1870
Georg Brandl268e4d42010-10-14 06:59:45 +00001871 def test_empty_zipfile(self):
1872 # Check that creating a file in 'w' or 'a' mode and closing without
1873 # adding any files to the archives creates a valid empty ZIP file
1874 zipf = zipfile.ZipFile(TESTFN, mode="w")
1875 zipf.close()
1876 try:
1877 zipf = zipfile.ZipFile(TESTFN, mode="r")
1878 except zipfile.BadZipFile:
1879 self.fail("Unable to create empty ZIP file in 'w' mode")
1880
1881 zipf = zipfile.ZipFile(TESTFN, mode="a")
1882 zipf.close()
1883 try:
1884 zipf = zipfile.ZipFile(TESTFN, mode="r")
1885 except:
1886 self.fail("Unable to create empty ZIP file in 'a' mode")
1887
1888 def test_open_empty_file(self):
1889 # Issue 1710703: Check that opening a file with less than 22 bytes
Georg Brandl4d540882010-10-28 06:42:33 +00001890 # raises a BadZipFile exception (rather than the previously unhelpful
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001891 # OSError)
Georg Brandl268e4d42010-10-14 06:59:45 +00001892 f = open(TESTFN, 'w')
1893 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001894 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN, 'r')
Georg Brandl268e4d42010-10-14 06:59:45 +00001895
Senthil Kumaran29fa9d42011-10-20 01:46:00 +08001896 def test_create_zipinfo_before_1980(self):
1897 self.assertRaises(ValueError,
1898 zipfile.ZipInfo, 'seventies', (1979, 1, 1, 0, 0, 0))
1899
Gregory P. Smith0af8a862014-05-29 23:42:14 -07001900 def test_zipfile_with_short_extra_field(self):
1901 """If an extra field in the header is less than 4 bytes, skip it."""
1902 zipdata = (
1903 b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1904 b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1905 b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1906 b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1907 b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1908 b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1909 b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1910 )
1911 with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1912 # testzip returns the name of the first corrupt file, or None
1913 self.assertIsNone(zipf.testzip())
1914
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001915 def test_open_conflicting_handles(self):
1916 # It's only possible to open one writable file handle at a time
1917 msg1 = b"It's fun to charter an accountant!"
1918 msg2 = b"And sail the wide accountant sea"
1919 msg3 = b"To find, explore the funds offshore"
1920 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
1921 with zipf.open('foo', mode='w') as w2:
1922 w2.write(msg1)
1923 with zipf.open('bar', mode='w') as w1:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001924 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001925 zipf.open('handle', mode='w')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001926 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001927 zipf.open('foo', mode='r')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001928 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001929 zipf.writestr('str', 'abcde')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001930 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001931 zipf.write(__file__, 'file')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001932 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001933 zipf.close()
1934 w1.write(msg2)
1935 with zipf.open('baz', mode='w') as w2:
1936 w2.write(msg3)
1937
1938 with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1939 self.assertEqual(zipf.read('foo'), msg1)
1940 self.assertEqual(zipf.read('bar'), msg2)
1941 self.assertEqual(zipf.read('baz'), msg3)
1942 self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
1943
John Jolly066df4f2018-01-30 01:51:35 -07001944 def test_seek_tell(self):
1945 # Test seek functionality
1946 txt = b"Where's Bruce?"
1947 bloc = txt.find(b"Bruce")
1948 # Check seek on a file
1949 with zipfile.ZipFile(TESTFN, "w") as zipf:
1950 zipf.writestr("foo.txt", txt)
1951 with zipfile.ZipFile(TESTFN, "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 # Check seek on memory file
1965 data = io.BytesIO()
1966 with zipfile.ZipFile(data, mode="w") as zipf:
1967 zipf.writestr("foo.txt", txt)
1968 with zipfile.ZipFile(data, mode="r") as zipf:
1969 with zipf.open("foo.txt", "r") as fp:
1970 fp.seek(bloc, os.SEEK_SET)
1971 self.assertEqual(fp.tell(), bloc)
1972 fp.seek(-bloc, os.SEEK_CUR)
1973 self.assertEqual(fp.tell(), 0)
1974 fp.seek(bloc, os.SEEK_CUR)
1975 self.assertEqual(fp.tell(), bloc)
1976 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1977 fp.seek(0, os.SEEK_END)
1978 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001979 fp.seek(0, os.SEEK_SET)
1980 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07001981
Miss Islington (bot)717cc612019-09-12 07:33:53 -07001982 @requires_bz2
1983 def test_decompress_without_3rd_party_library(self):
1984 data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1985 zip_file = io.BytesIO(data)
1986 with zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_BZIP2) as zf:
1987 zf.writestr('a.txt', b'a')
1988 with mock.patch('zipfile.bz2', None):
1989 with zipfile.ZipFile(zip_file) as zf:
1990 self.assertRaises(RuntimeError, zf.extract, 'a.txt')
1991
Guido van Rossumd8faa362007-04-27 19:54:29 +00001992 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00001993 unlink(TESTFN)
1994 unlink(TESTFN2)
1995
Thomas Wouterscf297e42007-02-23 15:07:44 +00001996
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001997class AbstractBadCrcTests:
1998 def test_testzip_with_bad_crc(self):
1999 """Tests that files with bad CRCs return their name from testzip."""
2000 zipdata = self.zip_with_bad_crc
2001
2002 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2003 # testzip returns the name of the first corrupt file, or None
2004 self.assertEqual('afile', zipf.testzip())
2005
2006 def test_read_with_bad_crc(self):
2007 """Tests that files with bad CRCs raise a BadZipFile exception when read."""
2008 zipdata = self.zip_with_bad_crc
2009
2010 # Using ZipFile.read()
2011 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2012 self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile')
2013
2014 # Using ZipExtFile.read()
2015 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2016 with zipf.open('afile', 'r') as corrupt_file:
2017 self.assertRaises(zipfile.BadZipFile, corrupt_file.read)
2018
2019 # Same with small reads (in order to exercise the buffering logic)
2020 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2021 with zipf.open('afile', 'r') as corrupt_file:
2022 corrupt_file.MIN_READ_SIZE = 2
2023 with self.assertRaises(zipfile.BadZipFile):
2024 while corrupt_file.read(2):
2025 pass
2026
2027
2028class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2029 compression = zipfile.ZIP_STORED
2030 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002031 b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
2032 b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
2033 b'ilehello,AworldP'
2034 b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
2035 b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
2036 b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
2037 b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
2038 b'\0\0/\0\0\0\0\0')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002039
2040@requires_zlib
2041class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2042 compression = zipfile.ZIP_DEFLATED
2043 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002044 b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
2045 b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2046 b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
2047 b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
2048 b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
2049 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
2050 b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
2051 b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002052
2053@requires_bz2
2054class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2055 compression = zipfile.ZIP_BZIP2
2056 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002057 b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA'
2058 b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2059 b'ileBZh91AY&SY\xd4\xa8\xca'
2060 b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5'
2061 b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f'
2062 b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14'
2063 b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8'
2064 b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'
2065 b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK'
2066 b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00'
2067 b'\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002068
2069@requires_lzma
2070class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2071 compression = zipfile.ZIP_LZMA
2072 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002073 b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2074 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2075 b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I'
2076 b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK'
2077 b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2078 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00'
2079 b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil'
2080 b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
2081 b'\x00>\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002082
2083
Thomas Wouterscf297e42007-02-23 15:07:44 +00002084class DecryptionTests(unittest.TestCase):
Ezio Melotti35386712009-12-31 13:22:41 +00002085 """Check that ZIP decryption works. Since the library does not
2086 support encryption at the moment, we use a pre-generated encrypted
2087 ZIP file."""
Thomas Wouterscf297e42007-02-23 15:07:44 +00002088
2089 data = (
Christian Tismer59202e52013-10-21 03:59:23 +02002090 b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
2091 b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
2092 b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
2093 b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
2094 b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
2095 b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
2096 b'\x00\x00L\x00\x00\x00\x00\x00' )
Christian Heimesfdab48e2008-01-20 09:06:41 +00002097 data2 = (
Christian Tismer59202e52013-10-21 03:59:23 +02002098 b'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
2099 b'\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
2100 b'\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
2101 b'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
2102 b'\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
2103 b'\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
2104 b'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
2105 b'\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
Thomas Wouterscf297e42007-02-23 15:07:44 +00002106
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002107 plain = b'zipfile.py encryption test'
Christian Heimesfdab48e2008-01-20 09:06:41 +00002108 plain2 = b'\x00'*512
Thomas Wouterscf297e42007-02-23 15:07:44 +00002109
2110 def setUp(self):
Ezio Melotti35386712009-12-31 13:22:41 +00002111 with open(TESTFN, "wb") as fp:
2112 fp.write(self.data)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002113 self.zip = zipfile.ZipFile(TESTFN, "r")
Ezio Melotti35386712009-12-31 13:22:41 +00002114 with open(TESTFN2, "wb") as fp:
2115 fp.write(self.data2)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002116 self.zip2 = zipfile.ZipFile(TESTFN2, "r")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002117
2118 def tearDown(self):
2119 self.zip.close()
2120 os.unlink(TESTFN)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002121 self.zip2.close()
2122 os.unlink(TESTFN2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002123
Ezio Melottiafd0d112009-07-15 17:17:17 +00002124 def test_no_password(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00002125 # Reading the encrypted file without password
2126 # must generate a RunTime exception
2127 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002128 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002129
Ezio Melottiafd0d112009-07-15 17:17:17 +00002130 def test_bad_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002131 self.zip.setpassword(b"perl")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002132 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002133 self.zip2.setpassword(b"perl")
2134 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Guido van Rossumd8faa362007-04-27 19:54:29 +00002135
Ezio Melotti975077a2011-05-19 22:03:22 +03002136 @requires_zlib
Ezio Melottiafd0d112009-07-15 17:17:17 +00002137 def test_good_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002138 self.zip.setpassword(b"python")
Ezio Melotti35386712009-12-31 13:22:41 +00002139 self.assertEqual(self.zip.read("test.txt"), self.plain)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002140 self.zip2.setpassword(b"12345")
Ezio Melotti35386712009-12-31 13:22:41 +00002141 self.assertEqual(self.zip2.read("zero"), self.plain2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002142
R. David Murray8d855d82010-12-21 21:53:37 +00002143 def test_unicode_password(self):
2144 self.assertRaises(TypeError, self.zip.setpassword, "unicode")
2145 self.assertRaises(TypeError, self.zip.read, "test.txt", "python")
2146 self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python")
2147 self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python")
2148
Miss Skeleton (bot)76fbdaa2019-10-27 01:40:44 -07002149 def test_seek_tell(self):
2150 self.zip.setpassword(b"python")
2151 txt = self.plain
2152 test_word = b'encryption'
2153 bloc = txt.find(test_word)
2154 bloc_len = len(test_word)
2155 with self.zip.open("test.txt", "r") as fp:
2156 fp.seek(bloc, os.SEEK_SET)
2157 self.assertEqual(fp.tell(), bloc)
2158 fp.seek(-bloc, os.SEEK_CUR)
2159 self.assertEqual(fp.tell(), 0)
2160 fp.seek(bloc, os.SEEK_CUR)
2161 self.assertEqual(fp.tell(), bloc)
2162 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2163
2164 # Make sure that the second read after seeking back beyond
2165 # _readbuffer returns the same content (ie. rewind to the start of
2166 # the file to read forward to the required position).
2167 old_read_size = fp.MIN_READ_SIZE
2168 fp.MIN_READ_SIZE = 1
2169 fp._readbuffer = b''
2170 fp._offset = 0
2171 fp.seek(0, os.SEEK_SET)
2172 self.assertEqual(fp.tell(), 0)
2173 fp.seek(bloc, os.SEEK_CUR)
2174 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2175 fp.MIN_READ_SIZE = old_read_size
2176
2177 fp.seek(0, os.SEEK_END)
2178 self.assertEqual(fp.tell(), len(txt))
2179 fp.seek(0, os.SEEK_SET)
2180 self.assertEqual(fp.tell(), 0)
2181
2182 # Read the file completely to definitely call any eof integrity
2183 # checks (crc) and make sure they still pass.
2184 fp.read()
2185
2186
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002187class AbstractTestsWithRandomBinaryFiles:
2188 @classmethod
2189 def setUpClass(cls):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002190 datacount = randint(16, 64)*1024 + randint(1, 1024)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002191 cls.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
2192 for i in range(datacount))
Guido van Rossumd8faa362007-04-27 19:54:29 +00002193
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002194 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002195 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +00002196 with open(TESTFN, "wb") as fp:
2197 fp.write(self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002198
2199 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002200 unlink(TESTFN)
2201 unlink(TESTFN2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002202
Ezio Melottiafd0d112009-07-15 17:17:17 +00002203 def make_test_archive(self, f, compression):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002204 # Create the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002205 with zipfile.ZipFile(f, "w", compression) as zipfp:
2206 zipfp.write(TESTFN, "another.name")
2207 zipfp.write(TESTFN, TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002208
Ezio Melottiafd0d112009-07-15 17:17:17 +00002209 def zip_test(self, f, compression):
2210 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002211
2212 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002213 with zipfile.ZipFile(f, "r", compression) as zipfp:
2214 testdata = zipfp.read(TESTFN)
2215 self.assertEqual(len(testdata), len(self.data))
2216 self.assertEqual(testdata, self.data)
2217 self.assertEqual(zipfp.read("another.name"), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002218
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002219 def test_read(self):
2220 for f in get_files(self):
2221 self.zip_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002222
Ezio Melottiafd0d112009-07-15 17:17:17 +00002223 def zip_open_test(self, f, compression):
2224 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002225
2226 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002227 with zipfile.ZipFile(f, "r", compression) as zipfp:
2228 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002229 with zipfp.open(TESTFN) as zipopen1:
2230 while True:
2231 read_data = zipopen1.read(256)
2232 if not read_data:
2233 break
2234 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002235
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002236 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002237 with zipfp.open("another.name") as zipopen2:
2238 while True:
2239 read_data = zipopen2.read(256)
2240 if not read_data:
2241 break
2242 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002243
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002244 testdata1 = b''.join(zipdata1)
2245 self.assertEqual(len(testdata1), len(self.data))
2246 self.assertEqual(testdata1, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002247
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002248 testdata2 = b''.join(zipdata2)
Ezio Melotti35386712009-12-31 13:22:41 +00002249 self.assertEqual(len(testdata2), len(self.data))
2250 self.assertEqual(testdata2, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002251
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002252 def test_open(self):
2253 for f in get_files(self):
2254 self.zip_open_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002255
Ezio Melottiafd0d112009-07-15 17:17:17 +00002256 def zip_random_open_test(self, f, compression):
2257 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002258
2259 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002260 with zipfile.ZipFile(f, "r", compression) as zipfp:
2261 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002262 with zipfp.open(TESTFN) as zipopen1:
2263 while True:
2264 read_data = zipopen1.read(randint(1, 1024))
2265 if not read_data:
2266 break
2267 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002268
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002269 testdata = b''.join(zipdata1)
2270 self.assertEqual(len(testdata), len(self.data))
2271 self.assertEqual(testdata, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002272
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002273 def test_random_open(self):
2274 for f in get_files(self):
2275 self.zip_random_open_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002276
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00002277
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002278class StoredTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2279 unittest.TestCase):
2280 compression = zipfile.ZIP_STORED
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02002281
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002282@requires_zlib
2283class DeflateTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2284 unittest.TestCase):
2285 compression = zipfile.ZIP_DEFLATED
2286
2287@requires_bz2
2288class Bzip2TestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2289 unittest.TestCase):
2290 compression = zipfile.ZIP_BZIP2
2291
2292@requires_lzma
2293class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2294 unittest.TestCase):
2295 compression = zipfile.ZIP_LZMA
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002296
Ezio Melotti76430242009-07-11 18:28:48 +00002297
luzpaza5293b42017-11-05 07:37:50 -06002298# Provide the tell() method but not seek()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002299class Tellable:
2300 def __init__(self, fp):
2301 self.fp = fp
2302 self.offset = 0
2303
2304 def write(self, data):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002305 n = self.fp.write(data)
2306 self.offset += n
2307 return n
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002308
2309 def tell(self):
2310 return self.offset
2311
2312 def flush(self):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002313 self.fp.flush()
2314
2315class Unseekable:
2316 def __init__(self, fp):
2317 self.fp = fp
2318
2319 def write(self, data):
2320 return self.fp.write(data)
2321
2322 def flush(self):
2323 self.fp.flush()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002324
2325class UnseekableTests(unittest.TestCase):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002326 def test_writestr(self):
2327 for wrapper in (lambda f: f), Tellable, Unseekable:
2328 with self.subTest(wrapper=wrapper):
2329 f = io.BytesIO()
2330 f.write(b'abc')
2331 bf = io.BufferedWriter(f)
2332 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2333 zipfp.writestr('ones', b'111')
2334 zipfp.writestr('twos', b'222')
2335 self.assertEqual(f.getvalue()[:5], b'abcPK')
2336 with zipfile.ZipFile(f, mode='r') as zipf:
2337 with zipf.open('ones') as zopen:
2338 self.assertEqual(zopen.read(), b'111')
2339 with zipf.open('twos') as zopen:
2340 self.assertEqual(zopen.read(), b'222')
2341
2342 def test_write(self):
2343 for wrapper in (lambda f: f), Tellable, Unseekable:
2344 with self.subTest(wrapper=wrapper):
2345 f = io.BytesIO()
2346 f.write(b'abc')
2347 bf = io.BufferedWriter(f)
2348 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2349 self.addCleanup(unlink, TESTFN)
2350 with open(TESTFN, 'wb') as f2:
2351 f2.write(b'111')
2352 zipfp.write(TESTFN, 'ones')
2353 with open(TESTFN, 'wb') as f2:
2354 f2.write(b'222')
2355 zipfp.write(TESTFN, 'twos')
2356 self.assertEqual(f.getvalue()[:5], b'abcPK')
2357 with zipfile.ZipFile(f, mode='r') as zipf:
2358 with zipf.open('ones') as zopen:
2359 self.assertEqual(zopen.read(), b'111')
2360 with zipf.open('twos') as zopen:
2361 self.assertEqual(zopen.read(), b'222')
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002362
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002363 def test_open_write(self):
2364 for wrapper in (lambda f: f), Tellable, Unseekable:
2365 with self.subTest(wrapper=wrapper):
2366 f = io.BytesIO()
2367 f.write(b'abc')
2368 bf = io.BufferedWriter(f)
2369 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
2370 with zipf.open('ones', 'w') as zopen:
2371 zopen.write(b'111')
2372 with zipf.open('twos', 'w') as zopen:
2373 zopen.write(b'222')
2374 self.assertEqual(f.getvalue()[:5], b'abcPK')
2375 with zipfile.ZipFile(f) as zipf:
2376 self.assertEqual(zipf.read('ones'), b'111')
2377 self.assertEqual(zipf.read('twos'), b'222')
2378
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002379
Ezio Melotti975077a2011-05-19 22:03:22 +03002380@requires_zlib
Guido van Rossumd8faa362007-04-27 19:54:29 +00002381class TestsWithMultipleOpens(unittest.TestCase):
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002382 @classmethod
2383 def setUpClass(cls):
2384 cls.data1 = b'111' + getrandbytes(10000)
2385 cls.data2 = b'222' + getrandbytes(10000)
2386
2387 def make_test_archive(self, f):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002388 # Create the ZIP archive
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002389 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
2390 zipfp.writestr('ones', self.data1)
2391 zipfp.writestr('twos', self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002392
Ezio Melottiafd0d112009-07-15 17:17:17 +00002393 def test_same_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002394 # Verify that (when the ZipFile is in control of creating file objects)
2395 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002396 for f in get_files(self):
2397 self.make_test_archive(f)
2398 with zipfile.ZipFile(f, mode="r") as zipf:
2399 with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
2400 data1 = zopen1.read(500)
2401 data2 = zopen2.read(500)
2402 data1 += zopen1.read()
2403 data2 += zopen2.read()
2404 self.assertEqual(data1, data2)
2405 self.assertEqual(data1, self.data1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002406
Ezio Melottiafd0d112009-07-15 17:17:17 +00002407 def test_different_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002408 # Verify that (when the ZipFile is in control of creating file objects)
2409 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002410 for f in get_files(self):
2411 self.make_test_archive(f)
2412 with zipfile.ZipFile(f, mode="r") as zipf:
2413 with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
2414 data1 = zopen1.read(500)
2415 data2 = zopen2.read(500)
2416 data1 += zopen1.read()
2417 data2 += zopen2.read()
2418 self.assertEqual(data1, self.data1)
2419 self.assertEqual(data2, self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002420
Ezio Melottiafd0d112009-07-15 17:17:17 +00002421 def test_interleaved(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002422 # Verify that (when the ZipFile is in control of creating file objects)
2423 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002424 for f in get_files(self):
2425 self.make_test_archive(f)
2426 with zipfile.ZipFile(f, mode="r") as zipf:
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002427 with zipf.open('ones') as zopen1:
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002428 data1 = zopen1.read(500)
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002429 with zipf.open('twos') as zopen2:
2430 data2 = zopen2.read(500)
2431 data1 += zopen1.read()
2432 data2 += zopen2.read()
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002433 self.assertEqual(data1, self.data1)
2434 self.assertEqual(data2, self.data2)
2435
2436 def test_read_after_close(self):
2437 for f in get_files(self):
2438 self.make_test_archive(f)
2439 with contextlib.ExitStack() as stack:
2440 with zipfile.ZipFile(f, 'r') as zipf:
2441 zopen1 = stack.enter_context(zipf.open('ones'))
2442 zopen2 = stack.enter_context(zipf.open('twos'))
Brian Curtin8fb9b862010-11-18 02:15:28 +00002443 data1 = zopen1.read(500)
2444 data2 = zopen2.read(500)
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002445 data1 += zopen1.read()
2446 data2 += zopen2.read()
2447 self.assertEqual(data1, self.data1)
2448 self.assertEqual(data2, self.data2)
2449
2450 def test_read_after_write(self):
2451 for f in get_files(self):
2452 with zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as zipf:
2453 zipf.writestr('ones', self.data1)
2454 zipf.writestr('twos', self.data2)
2455 with zipf.open('ones') as zopen1:
2456 data1 = zopen1.read(500)
2457 self.assertEqual(data1, self.data1[:500])
2458 with zipfile.ZipFile(f, 'r') as zipf:
2459 data1 = zipf.read('ones')
2460 data2 = zipf.read('twos')
2461 self.assertEqual(data1, self.data1)
2462 self.assertEqual(data2, self.data2)
2463
2464 def test_write_after_read(self):
2465 for f in get_files(self):
2466 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipf:
2467 zipf.writestr('ones', self.data1)
2468 with zipf.open('ones') as zopen1:
2469 zopen1.read(500)
2470 zipf.writestr('twos', self.data2)
2471 with zipfile.ZipFile(f, 'r') as zipf:
2472 data1 = zipf.read('ones')
2473 data2 = zipf.read('twos')
2474 self.assertEqual(data1, self.data1)
2475 self.assertEqual(data2, self.data2)
2476
2477 def test_many_opens(self):
2478 # Verify that read() and open() promptly close the file descriptor,
2479 # and don't rely on the garbage collector to free resources.
2480 self.make_test_archive(TESTFN2)
2481 with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
2482 for x in range(100):
2483 zipf.read('ones')
2484 with zipf.open('ones') as zopen1:
2485 pass
2486 with open(os.devnull) as f:
2487 self.assertLess(f.fileno(), 100)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002488
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002489 def test_write_while_reading(self):
2490 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
2491 zipf.writestr('ones', self.data1)
2492 with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
2493 with zipf.open('ones', 'r') as r1:
2494 data1 = r1.read(500)
2495 with zipf.open('twos', 'w') as w1:
2496 w1.write(self.data2)
2497 data1 += r1.read()
2498 self.assertEqual(data1, self.data1)
2499 with zipfile.ZipFile(TESTFN2) as zipf:
2500 self.assertEqual(zipf.read('twos'), self.data2)
2501
Guido van Rossumd8faa362007-04-27 19:54:29 +00002502 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002503 unlink(TESTFN2)
2504
Guido van Rossumd8faa362007-04-27 19:54:29 +00002505
Martin v. Löwis59e47792009-01-24 14:10:07 +00002506class TestWithDirectory(unittest.TestCase):
2507 def setUp(self):
2508 os.mkdir(TESTFN2)
2509
Ezio Melottiafd0d112009-07-15 17:17:17 +00002510 def test_extract_dir(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002511 with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
2512 zipf.extractall(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002513 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
2514 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
2515 self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
2516
Ezio Melottiafd0d112009-07-15 17:17:17 +00002517 def test_bug_6050(self):
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002518 # Extraction should succeed if directories already exist
2519 os.mkdir(os.path.join(TESTFN2, "a"))
Ezio Melottiafd0d112009-07-15 17:17:17 +00002520 self.test_extract_dir()
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002521
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002522 def test_write_dir(self):
2523 dirpath = os.path.join(TESTFN2, "x")
2524 os.mkdir(dirpath)
2525 mode = os.stat(dirpath).st_mode & 0xFFFF
2526 with zipfile.ZipFile(TESTFN, "w") as zipf:
2527 zipf.write(dirpath)
2528 zinfo = zipf.filelist[0]
2529 self.assertTrue(zinfo.filename.endswith("/x/"))
2530 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2531 zipf.write(dirpath, "y")
2532 zinfo = zipf.filelist[1]
2533 self.assertTrue(zinfo.filename, "y/")
2534 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2535 with zipfile.ZipFile(TESTFN, "r") as zipf:
2536 zinfo = zipf.filelist[0]
2537 self.assertTrue(zinfo.filename.endswith("/x/"))
2538 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2539 zinfo = zipf.filelist[1]
2540 self.assertTrue(zinfo.filename, "y/")
2541 self.assertEqual(zinfo.external_attr, (mode << 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, "y")))
2546 self.assertEqual(len(os.listdir(target)), 2)
2547
2548 def test_writestr_dir(self):
Martin v. Löwis59e47792009-01-24 14:10:07 +00002549 os.mkdir(os.path.join(TESTFN2, "x"))
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002550 with zipfile.ZipFile(TESTFN, "w") as zipf:
2551 zipf.writestr("x/", b'')
2552 zinfo = zipf.filelist[0]
2553 self.assertEqual(zinfo.filename, "x/")
2554 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2555 with zipfile.ZipFile(TESTFN, "r") as zipf:
2556 zinfo = zipf.filelist[0]
2557 self.assertTrue(zinfo.filename.endswith("x/"))
2558 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2559 target = os.path.join(TESTFN2, "target")
2560 os.mkdir(target)
2561 zipf.extractall(target)
2562 self.assertTrue(os.path.isdir(os.path.join(target, "x")))
2563 self.assertEqual(os.listdir(target), ["x"])
Martin v. Löwis59e47792009-01-24 14:10:07 +00002564
2565 def tearDown(self):
Victor Stinner57004c62014-09-04 00:49:01 +02002566 rmtree(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002567 if os.path.exists(TESTFN):
Ezio Melotti76430242009-07-11 18:28:48 +00002568 unlink(TESTFN)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002569
Guido van Rossumd8faa362007-04-27 19:54:29 +00002570
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002571class ZipInfoTests(unittest.TestCase):
2572 def test_from_file(self):
2573 zi = zipfile.ZipInfo.from_file(__file__)
2574 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2575 self.assertFalse(zi.is_dir())
Serhiy Storchaka8606e952017-03-08 14:37:51 +02002576 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2577
2578 def test_from_file_pathlike(self):
2579 zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
2580 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2581 self.assertFalse(zi.is_dir())
2582 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2583
2584 def test_from_file_bytes(self):
2585 zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
2586 self.assertEqual(posixpath.basename(zi.filename), 'test')
2587 self.assertFalse(zi.is_dir())
2588 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2589
2590 def test_from_file_fileno(self):
2591 with open(__file__, 'rb') as f:
2592 zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
2593 self.assertEqual(posixpath.basename(zi.filename), 'test')
2594 self.assertFalse(zi.is_dir())
2595 self.assertEqual(zi.file_size, os.path.getsize(__file__))
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002596
2597 def test_from_dir(self):
2598 dirpath = os.path.dirname(os.path.abspath(__file__))
2599 zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
2600 self.assertEqual(zi.filename, 'stdlib_tests/')
2601 self.assertTrue(zi.is_dir())
2602 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
2603 self.assertEqual(zi.file_size, 0)
2604
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002605
2606class CommandLineTest(unittest.TestCase):
2607
2608 def zipfilecmd(self, *args, **kwargs):
2609 rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args,
2610 **kwargs)
2611 return out.replace(os.linesep.encode(), b'\n')
2612
2613 def zipfilecmd_failure(self, *args):
2614 return script_helper.assert_python_failure('-m', 'zipfile', *args)
2615
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002616 def test_bad_use(self):
2617 rc, out, err = self.zipfilecmd_failure()
2618 self.assertEqual(out, b'')
2619 self.assertIn(b'usage', err.lower())
2620 self.assertIn(b'error', err.lower())
2621 self.assertIn(b'required', err.lower())
2622 rc, out, err = self.zipfilecmd_failure('-l', '')
2623 self.assertEqual(out, b'')
2624 self.assertNotEqual(err.strip(), b'')
2625
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002626 def test_test_command(self):
2627 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002628 for opt in '-t', '--test':
2629 out = self.zipfilecmd(opt, zip_name)
2630 self.assertEqual(out.rstrip(), b'Done testing')
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002631 zip_name = findfile('testtar.tar')
2632 rc, out, err = self.zipfilecmd_failure('-t', zip_name)
2633 self.assertEqual(out, b'')
2634
2635 def test_list_command(self):
2636 zip_name = findfile('zipdir.zip')
2637 t = io.StringIO()
2638 with zipfile.ZipFile(zip_name, 'r') as tf:
2639 tf.printdir(t)
2640 expected = t.getvalue().encode('ascii', 'backslashreplace')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002641 for opt in '-l', '--list':
2642 out = self.zipfilecmd(opt, zip_name,
2643 PYTHONIOENCODING='ascii:backslashreplace')
2644 self.assertEqual(out, expected)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002645
Serhiy Storchakab4293ef2016-10-23 22:32:30 +03002646 @requires_zlib
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002647 def test_create_command(self):
2648 self.addCleanup(unlink, TESTFN)
2649 with open(TESTFN, 'w') as f:
2650 f.write('test 1')
2651 os.mkdir(TESTFNDIR)
2652 self.addCleanup(rmtree, TESTFNDIR)
2653 with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f:
2654 f.write('test 2')
2655 files = [TESTFN, TESTFNDIR]
2656 namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt']
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002657 for opt in '-c', '--create':
2658 try:
2659 out = self.zipfilecmd(opt, TESTFN2, *files)
2660 self.assertEqual(out, b'')
2661 with zipfile.ZipFile(TESTFN2) as zf:
2662 self.assertEqual(zf.namelist(), namelist)
2663 self.assertEqual(zf.read(namelist[0]), b'test 1')
2664 self.assertEqual(zf.read(namelist[2]), b'test 2')
2665 finally:
2666 unlink(TESTFN2)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002667
2668 def test_extract_command(self):
2669 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002670 for opt in '-e', '--extract':
2671 with temp_dir() as extdir:
2672 out = self.zipfilecmd(opt, zip_name, extdir)
2673 self.assertEqual(out, b'')
2674 with zipfile.ZipFile(zip_name) as zf:
2675 for zi in zf.infolist():
2676 path = os.path.join(extdir,
2677 zi.filename.replace('/', os.sep))
2678 if zi.is_dir():
2679 self.assertTrue(os.path.isdir(path))
2680 else:
2681 self.assertTrue(os.path.isfile(path))
2682 with open(path, 'rb') as f:
2683 self.assertEqual(f.read(), zf.read(zi))
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002684
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002685
2686# Poor man's technique to consume a (smallish) iterable.
2687consume = tuple
2688
2689
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002690def add_dirs(zf):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002691 """
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002692 Given a writable zip file zf, inject directory entries for
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002693 any directories implied by the presence of children.
2694 """
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002695 for name in zipfile.Path._implied_dirs(zf.namelist()):
2696 zf.writestr(name, b"")
2697 return zf
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002698
2699
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002700def build_alpharep_fixture():
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002701 """
2702 Create a zip file with this structure:
2703
2704 .
2705 ├── a.txt
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002706 ├── b
2707 │ ├── c.txt
2708 │ ├── d
2709 │ │ └── e.txt
2710 │ └── f.txt
2711 └── g
2712 └── h
2713 └── i.txt
2714
2715 This fixture has the following key characteristics:
2716
2717 - a file at the root (a)
2718 - a file two levels deep (b/d/e)
2719 - multiple files in a directory (b/c, b/f)
2720 - a directory containing only a directory (g/h)
2721
2722 "alpha" because it uses alphabet
2723 "rep" because it's a representative example
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002724 """
2725 data = io.BytesIO()
2726 zf = zipfile.ZipFile(data, "w")
2727 zf.writestr("a.txt", b"content of a")
2728 zf.writestr("b/c.txt", b"content of c")
2729 zf.writestr("b/d/e.txt", b"content of e")
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002730 zf.writestr("b/f.txt", b"content of f")
2731 zf.writestr("g/h/i.txt", b"content of i")
2732 zf.filename = "alpharep.zip"
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002733 return zf
2734
2735
Miss Islington (bot)74b02912019-09-10 15:57:54 -07002736class TestExecutablePrependedZip(unittest.TestCase):
2737 """Test our ability to open zip files with an executable prepended."""
2738
2739 def setUp(self):
2740 self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
2741 self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
2742
2743 def _test_zip_works(self, name):
2744 # bpo-28494 sanity check: ensure is_zipfile works on these.
2745 self.assertTrue(zipfile.is_zipfile(name),
2746 f'is_zipfile failed on {name}')
2747 # Ensure we can operate on these via ZipFile.
2748 with zipfile.ZipFile(name) as zipfp:
2749 for n in zipfp.namelist():
2750 data = zipfp.read(n)
2751 self.assertIn(b'FAVORITE_NUMBER', data)
2752
2753 def test_read_zip_with_exe_prepended(self):
2754 self._test_zip_works(self.exe_zip)
2755
2756 def test_read_zip64_with_exe_prepended(self):
2757 self._test_zip_works(self.exe_zip64)
2758
2759 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2760 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2761 'Test relies on #!/bin/bash working.')
2762 def test_execute_zip2(self):
2763 output = subprocess.check_output([self.exe_zip, sys.executable])
2764 self.assertIn(b'number in executable: 5', output)
2765
2766 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2767 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2768 'Test relies on #!/bin/bash working.')
2769 def test_execute_zip64(self):
2770 output = subprocess.check_output([self.exe_zip64, sys.executable])
2771 self.assertIn(b'number in executable: 5', output)
2772
2773
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002774class TestPath(unittest.TestCase):
2775 def setUp(self):
2776 self.fixtures = contextlib.ExitStack()
2777 self.addCleanup(self.fixtures.close)
2778
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002779 def zipfile_alpharep(self):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002780 with self.subTest():
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002781 yield build_alpharep_fixture()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002782 with self.subTest():
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002783 yield add_dirs(build_alpharep_fixture())
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002784
2785 def zipfile_ondisk(self):
2786 tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002787 for alpharep in self.zipfile_alpharep():
2788 buffer = alpharep.fp
2789 alpharep.close()
2790 path = tmpdir / alpharep.filename
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002791 with path.open("wb") as strm:
2792 strm.write(buffer.getvalue())
2793 yield path
2794
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002795 def test_iterdir_and_types(self):
2796 for alpharep in self.zipfile_alpharep():
2797 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002798 assert root.is_dir()
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002799 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002800 assert a.is_file()
2801 assert b.is_dir()
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002802 assert g.is_dir()
2803 c, f, d = b.iterdir()
2804 assert c.is_file() and f.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002805 e, = d.iterdir()
2806 assert e.is_file()
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002807 h, = g.iterdir()
2808 i, = h.iterdir()
2809 assert i.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002810
2811 def test_open(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002812 for alpharep in self.zipfile_alpharep():
2813 root = zipfile.Path(alpharep)
2814 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002815 with a.open() as strm:
2816 data = strm.read()
2817 assert data == b"content of a"
2818
2819 def test_read(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002820 for alpharep in self.zipfile_alpharep():
2821 root = zipfile.Path(alpharep)
2822 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002823 assert a.read_text() == "content of a"
2824 assert a.read_bytes() == b"content of a"
2825
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002826 def test_joinpath(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002827 for alpharep in self.zipfile_alpharep():
2828 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002829 a = root.joinpath("a")
2830 assert a.is_file()
2831 e = root.joinpath("b").joinpath("d").joinpath("e.txt")
2832 assert e.read_text() == "content of e"
2833
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002834 def test_traverse_truediv(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002835 for alpharep in self.zipfile_alpharep():
2836 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002837 a = root / "a"
2838 assert a.is_file()
2839 e = root / "b" / "d" / "e.txt"
2840 assert e.read_text() == "content of e"
2841
2842 def test_pathlike_construction(self):
2843 """
2844 zipfile.Path should be constructable from a path-like object
2845 """
2846 for zipfile_ondisk in self.zipfile_ondisk():
2847 pathlike = pathlib.Path(str(zipfile_ondisk))
2848 zipfile.Path(pathlike)
2849
2850 def test_traverse_pathlike(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002851 for alpharep in self.zipfile_alpharep():
2852 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002853 root / pathlib.Path("a")
2854
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002855 def test_parent(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002856 for alpharep in self.zipfile_alpharep():
2857 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002858 assert (root / 'a').parent.at == ''
2859 assert (root / 'a' / 'b').parent.at == 'a/'
2860
Miss Islington (bot)66905d12019-07-07 15:05:53 -07002861 def test_dir_parent(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002862 for alpharep in self.zipfile_alpharep():
2863 root = zipfile.Path(alpharep)
Miss Islington (bot)66905d12019-07-07 15:05:53 -07002864 assert (root / 'b').parent.at == ''
2865 assert (root / 'b/').parent.at == ''
2866
2867 def test_missing_dir_parent(self):
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002868 for alpharep in self.zipfile_alpharep():
2869 root = zipfile.Path(alpharep)
Miss Islington (bot)66905d12019-07-07 15:05:53 -07002870 assert (root / 'missing dir/').parent.at == ''
2871
Miss Islington (bot)c410f382019-08-24 09:03:52 -07002872
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00002873if __name__ == "__main__":
Brett Cannond5b4e1d2013-06-12 19:57:19 -04002874 unittest.main()