test_zipfile.py revision c328d11ef184e706e42149d740d99044d7d8981a
1# We can test part of the module without zlib.
2try:
3    import zlib
4except ImportError:
5    zlib = None
6
7import os
8import io
9import sys
10import time
11import struct
12import zipfile
13import unittest
14
15from StringIO import StringIO
16from tempfile import TemporaryFile
17from random import randint, random, getrandbits
18from unittest import skipUnless
19
20from test.test_support import TESTFN, TESTFN_UNICODE, TESTFN_ENCODING, \
21                              run_unittest, findfile, unlink, rmtree, check_warnings
22try:
23    TESTFN_UNICODE.encode(TESTFN_ENCODING)
24except (UnicodeError, TypeError):
25    # Either the file system encoding is None, or the file name
26    # cannot be encoded in the file system encoding.
27    TESTFN_UNICODE = None
28
29TESTFN2 = TESTFN + "2"
30TESTFNDIR = TESTFN + "d"
31FIXEDTEST_SIZE = 1000
32
33SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
34                   ('ziptest2dir/_ziptest2', 'qawsedrftg'),
35                   ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
36                   ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')]
37
38def getrandbytes(size):
39    return bytes(bytearray.fromhex('%0*x' % (2 * size, getrandbits(8 * size))))
40
41class TestsWithSourceFile(unittest.TestCase):
42    def setUp(self):
43        self.line_gen = ["Zipfile test line %d. random float: %f" % (i, random())
44                         for i in xrange(FIXEDTEST_SIZE)]
45        self.data = '\n'.join(self.line_gen) + '\n'
46
47        # Make a source file with some lines
48        with open(TESTFN, "wb") as fp:
49            fp.write(self.data)
50
51    def make_test_archive(self, f, compression):
52        # Create the ZIP archive
53        with zipfile.ZipFile(f, "w", compression) as zipfp:
54            zipfp.write(TESTFN, "another.name")
55            zipfp.write(TESTFN, TESTFN)
56            zipfp.writestr("strfile", self.data)
57
58    def zip_test(self, f, compression):
59        self.make_test_archive(f, compression)
60
61        # Read the ZIP archive
62        with zipfile.ZipFile(f, "r", compression) as zipfp:
63            self.assertEqual(zipfp.read(TESTFN), self.data)
64            self.assertEqual(zipfp.read("another.name"), self.data)
65            self.assertEqual(zipfp.read("strfile"), self.data)
66
67            # Print the ZIP directory
68            fp = StringIO()
69            stdout = sys.stdout
70            try:
71                sys.stdout = fp
72                zipfp.printdir()
73            finally:
74                sys.stdout = stdout
75
76            directory = fp.getvalue()
77            lines = directory.splitlines()
78            self.assertEqual(len(lines), 4) # Number of files + header
79
80            self.assertIn('File Name', lines[0])
81            self.assertIn('Modified', lines[0])
82            self.assertIn('Size', lines[0])
83
84            fn, date, time_, size = lines[1].split()
85            self.assertEqual(fn, 'another.name')
86            self.assertTrue(time.strptime(date, '%Y-%m-%d'))
87            self.assertTrue(time.strptime(time_, '%H:%M:%S'))
88            self.assertEqual(size, str(len(self.data)))
89
90            # Check the namelist
91            names = zipfp.namelist()
92            self.assertEqual(len(names), 3)
93            self.assertIn(TESTFN, names)
94            self.assertIn("another.name", names)
95            self.assertIn("strfile", names)
96
97            # Check infolist
98            infos = zipfp.infolist()
99            names = [i.filename for i in infos]
100            self.assertEqual(len(names), 3)
101            self.assertIn(TESTFN, names)
102            self.assertIn("another.name", names)
103            self.assertIn("strfile", names)
104            for i in infos:
105                self.assertEqual(i.file_size, len(self.data))
106
107            # check getinfo
108            for nm in (TESTFN, "another.name", "strfile"):
109                info = zipfp.getinfo(nm)
110                self.assertEqual(info.filename, nm)
111                self.assertEqual(info.file_size, len(self.data))
112
113            # Check that testzip doesn't raise an exception
114            zipfp.testzip()
115
116    def test_stored(self):
117        for f in (TESTFN2, TemporaryFile(), StringIO()):
118            self.zip_test(f, zipfile.ZIP_STORED)
119
120    def zip_open_test(self, f, compression):
121        self.make_test_archive(f, compression)
122
123        # Read the ZIP archive
124        with zipfile.ZipFile(f, "r", compression) as zipfp:
125            zipdata1 = []
126            with zipfp.open(TESTFN) as zipopen1:
127                while True:
128                    read_data = zipopen1.read(256)
129                    if not read_data:
130                        break
131                    zipdata1.append(read_data)
132
133            zipdata2 = []
134            with zipfp.open("another.name") as zipopen2:
135                while True:
136                    read_data = zipopen2.read(256)
137                    if not read_data:
138                        break
139                    zipdata2.append(read_data)
140
141            self.assertEqual(''.join(zipdata1), self.data)
142            self.assertEqual(''.join(zipdata2), self.data)
143
144    def test_open_stored(self):
145        for f in (TESTFN2, TemporaryFile(), StringIO()):
146            self.zip_open_test(f, zipfile.ZIP_STORED)
147
148    def test_open_via_zip_info(self):
149        # Create the ZIP archive
150        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
151            zipfp.writestr("name", "foo")
152            with check_warnings(('', UserWarning)):
153                zipfp.writestr("name", "bar")
154            self.assertEqual(zipfp.namelist(), ["name"] * 2)
155
156        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
157            infos = zipfp.infolist()
158            data = ""
159            for info in infos:
160                with zipfp.open(info) as f:
161                    data += f.read()
162            self.assertTrue(data == "foobar" or data == "barfoo")
163            data = ""
164            for info in infos:
165                data += zipfp.read(info)
166            self.assertTrue(data == "foobar" or data == "barfoo")
167
168    def zip_random_open_test(self, f, compression):
169        self.make_test_archive(f, compression)
170
171        # Read the ZIP archive
172        with zipfile.ZipFile(f, "r", compression) as zipfp:
173            zipdata1 = []
174            with zipfp.open(TESTFN) as zipopen1:
175                while True:
176                    read_data = zipopen1.read(randint(1, 1024))
177                    if not read_data:
178                        break
179                    zipdata1.append(read_data)
180
181            self.assertEqual(''.join(zipdata1), self.data)
182
183    def test_random_open_stored(self):
184        for f in (TESTFN2, TemporaryFile(), StringIO()):
185            self.zip_random_open_test(f, zipfile.ZIP_STORED)
186
187    def test_univeral_readaheads(self):
188        f = StringIO()
189
190        data = 'a\r\n' * 16 * 1024
191        with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp:
192            zipfp.writestr(TESTFN, data)
193
194        data2 = ''
195        with zipfile.ZipFile(f, 'r') as zipfp:
196            with zipfp.open(TESTFN, 'rU') as zipopen:
197                for line in zipopen:
198                    data2 += line
199
200        self.assertEqual(data, data2.replace('\n', '\r\n'))
201
202    def zip_readline_read_test(self, f, compression):
203        self.make_test_archive(f, compression)
204
205        # Read the ZIP archive
206        with zipfile.ZipFile(f, "r") as zipfp:
207            with zipfp.open(TESTFN) as zipopen:
208                data = ''
209                while True:
210                    read = zipopen.readline()
211                    if not read:
212                        break
213                    data += read
214
215                    read = zipopen.read(100)
216                    if not read:
217                        break
218                    data += read
219
220        self.assertEqual(data, self.data)
221
222    def zip_readline_test(self, f, compression):
223        self.make_test_archive(f, compression)
224
225        # Read the ZIP archive
226        with zipfile.ZipFile(f, "r") as zipfp:
227            with zipfp.open(TESTFN) as zipopen:
228                for line in self.line_gen:
229                    linedata = zipopen.readline()
230                    self.assertEqual(linedata, line + '\n')
231
232    def zip_readlines_test(self, f, compression):
233        self.make_test_archive(f, compression)
234
235        # Read the ZIP archive
236        with zipfile.ZipFile(f, "r") as zipfp:
237            with zipfp.open(TESTFN) as zo:
238                ziplines = zo.readlines()
239                for line, zipline in zip(self.line_gen, ziplines):
240                    self.assertEqual(zipline, line + '\n')
241
242    def zip_iterlines_test(self, f, compression):
243        self.make_test_archive(f, compression)
244
245        # Read the ZIP archive
246        with zipfile.ZipFile(f, "r") as zipfp:
247            for line, zipline in zip(self.line_gen, zipfp.open(TESTFN)):
248                self.assertEqual(zipline, line + '\n')
249
250    def test_readline_read_stored(self):
251        # Issue #7610: calls to readline() interleaved with calls to read().
252        for f in (TESTFN2, TemporaryFile(), StringIO()):
253            self.zip_readline_read_test(f, zipfile.ZIP_STORED)
254
255    def test_readline_stored(self):
256        for f in (TESTFN2, TemporaryFile(), StringIO()):
257            self.zip_readline_test(f, zipfile.ZIP_STORED)
258
259    def test_readlines_stored(self):
260        for f in (TESTFN2, TemporaryFile(), StringIO()):
261            self.zip_readlines_test(f, zipfile.ZIP_STORED)
262
263    def test_iterlines_stored(self):
264        for f in (TESTFN2, TemporaryFile(), StringIO()):
265            self.zip_iterlines_test(f, zipfile.ZIP_STORED)
266
267    @skipUnless(zlib, "requires zlib")
268    def test_deflated(self):
269        for f in (TESTFN2, TemporaryFile(), StringIO()):
270            self.zip_test(f, zipfile.ZIP_DEFLATED)
271
272    @skipUnless(zlib, "requires zlib")
273    def test_open_deflated(self):
274        for f in (TESTFN2, TemporaryFile(), StringIO()):
275            self.zip_open_test(f, zipfile.ZIP_DEFLATED)
276
277    @skipUnless(zlib, "requires zlib")
278    def test_random_open_deflated(self):
279        for f in (TESTFN2, TemporaryFile(), StringIO()):
280            self.zip_random_open_test(f, zipfile.ZIP_DEFLATED)
281
282    @skipUnless(zlib, "requires zlib")
283    def test_readline_read_deflated(self):
284        # Issue #7610: calls to readline() interleaved with calls to read().
285        for f in (TESTFN2, TemporaryFile(), StringIO()):
286            self.zip_readline_read_test(f, zipfile.ZIP_DEFLATED)
287
288    @skipUnless(zlib, "requires zlib")
289    def test_readline_deflated(self):
290        for f in (TESTFN2, TemporaryFile(), StringIO()):
291            self.zip_readline_test(f, zipfile.ZIP_DEFLATED)
292
293    @skipUnless(zlib, "requires zlib")
294    def test_readlines_deflated(self):
295        for f in (TESTFN2, TemporaryFile(), StringIO()):
296            self.zip_readlines_test(f, zipfile.ZIP_DEFLATED)
297
298    @skipUnless(zlib, "requires zlib")
299    def test_iterlines_deflated(self):
300        for f in (TESTFN2, TemporaryFile(), StringIO()):
301            self.zip_iterlines_test(f, zipfile.ZIP_DEFLATED)
302
303    @skipUnless(zlib, "requires zlib")
304    def test_low_compression(self):
305        """Check for cases where compressed data is larger than original."""
306        # Create the ZIP archive
307        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
308            zipfp.writestr("strfile", '12')
309
310        # Get an open object for strfile
311        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp:
312            with zipfp.open("strfile") as openobj:
313                self.assertEqual(openobj.read(1), '1')
314                self.assertEqual(openobj.read(1), '2')
315
316    def test_absolute_arcnames(self):
317        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
318            zipfp.write(TESTFN, "/absolute")
319
320        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
321            self.assertEqual(zipfp.namelist(), ["absolute"])
322
323    def test_append_to_zip_file(self):
324        """Test appending to an existing zipfile."""
325        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
326            zipfp.write(TESTFN, TESTFN)
327
328        with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
329            zipfp.writestr("strfile", self.data)
330            self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
331
332    def test_append_to_non_zip_file(self):
333        """Test appending to an existing file that is not a zipfile."""
334        # NOTE: this test fails if len(d) < 22 because of the first
335        # line "fpin.seek(-22, 2)" in _EndRecData
336        data = 'I am not a ZipFile!'*10
337        with open(TESTFN2, 'wb') as f:
338            f.write(data)
339
340        with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
341            zipfp.write(TESTFN, TESTFN)
342
343        with open(TESTFN2, 'rb') as f:
344            f.seek(len(data))
345            with zipfile.ZipFile(f, "r") as zipfp:
346                self.assertEqual(zipfp.namelist(), [TESTFN])
347
348    def test_ignores_newline_at_end(self):
349        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
350            zipfp.write(TESTFN, TESTFN)
351        with open(TESTFN2, 'a') as f:
352            f.write("\r\n\00\00\00")
353        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
354            self.assertIsInstance(zipfp, zipfile.ZipFile)
355
356    def test_ignores_stuff_appended_past_comments(self):
357        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
358            zipfp.comment = b"this is a comment"
359            zipfp.write(TESTFN, TESTFN)
360        with open(TESTFN2, 'a') as f:
361            f.write("abcdef\r\n")
362        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
363            self.assertIsInstance(zipfp, zipfile.ZipFile)
364            self.assertEqual(zipfp.comment, b"this is a comment")
365
366    def test_write_default_name(self):
367        """Check that calling ZipFile.write without arcname specified
368        produces the expected result."""
369        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
370            zipfp.write(TESTFN)
371            with open(TESTFN,'r') as fid:
372                self.assertEqual(zipfp.read(TESTFN), fid.read())
373
374    @skipUnless(zlib, "requires zlib")
375    def test_per_file_compression(self):
376        """Check that files within a Zip archive can have different
377        compression options."""
378        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
379            zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
380            zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
381            sinfo = zipfp.getinfo('storeme')
382            dinfo = zipfp.getinfo('deflateme')
383            self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
384            self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
385
386    def test_write_to_readonly(self):
387        """Check that trying to call write() on a readonly ZipFile object
388        raises a RuntimeError."""
389        with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
390            zipfp.writestr("somefile.txt", "bogus")
391
392        with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
393            self.assertRaises(RuntimeError, zipfp.write, TESTFN)
394
395    def test_extract(self):
396        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
397            for fpath, fdata in SMALL_TEST_DATA:
398                zipfp.writestr(fpath, fdata)
399
400        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
401            for fpath, fdata in SMALL_TEST_DATA:
402                writtenfile = zipfp.extract(fpath)
403
404                # make sure it was written to the right place
405                correctfile = os.path.join(os.getcwd(), fpath)
406                correctfile = os.path.normpath(correctfile)
407
408                self.assertEqual(writtenfile, correctfile)
409
410                # make sure correct data is in correct file
411                with open(writtenfile, "rb") as fid:
412                    self.assertEqual(fdata, fid.read())
413                os.remove(writtenfile)
414
415        # remove the test file subdirectories
416        rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
417
418    def test_extract_all(self):
419        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
420            for fpath, fdata in SMALL_TEST_DATA:
421                zipfp.writestr(fpath, fdata)
422
423        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
424            zipfp.extractall()
425            for fpath, fdata in SMALL_TEST_DATA:
426                outfile = os.path.join(os.getcwd(), fpath)
427
428                with open(outfile, "rb") as fid:
429                    self.assertEqual(fdata, fid.read())
430                os.remove(outfile)
431
432        # remove the test file subdirectories
433        rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
434
435    def check_file(self, filename, content):
436        self.assertTrue(os.path.isfile(filename))
437        with open(filename, 'rb') as f:
438            self.assertEqual(f.read(), content)
439
440    @skipUnless(TESTFN_UNICODE, "No Unicode filesystem semantics on this platform.")
441    def test_extract_unicode_filenames(self):
442        fnames = [u'foo.txt', os.path.basename(TESTFN_UNICODE)]
443        content = 'Test for unicode filename'
444        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
445            for fname in fnames:
446                zipfp.writestr(fname, content)
447
448        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
449            for fname in fnames:
450                writtenfile = zipfp.extract(fname)
451
452                # make sure it was written to the right place
453                correctfile = os.path.join(os.getcwd(), fname)
454                correctfile = os.path.normpath(correctfile)
455                self.assertEqual(writtenfile, correctfile)
456
457                self.check_file(writtenfile, content)
458                os.remove(writtenfile)
459
460    def test_extract_hackers_arcnames(self):
461        hacknames = [
462            ('../foo/bar', 'foo/bar'),
463            ('foo/../bar', 'foo/bar'),
464            ('foo/../../bar', 'foo/bar'),
465            ('foo/bar/..', 'foo/bar'),
466            ('./../foo/bar', 'foo/bar'),
467            ('/foo/bar', 'foo/bar'),
468            ('/foo/../bar', 'foo/bar'),
469            ('/foo/../../bar', 'foo/bar'),
470        ]
471        if os.path.sep == '\\':
472            hacknames.extend([
473                (r'..\foo\bar', 'foo/bar'),
474                (r'..\/foo\/bar', 'foo/bar'),
475                (r'foo/\..\/bar', 'foo/bar'),
476                (r'foo\/../\bar', 'foo/bar'),
477                (r'C:foo/bar', 'foo/bar'),
478                (r'C:/foo/bar', 'foo/bar'),
479                (r'C://foo/bar', 'foo/bar'),
480                (r'C:\foo\bar', 'foo/bar'),
481                (r'//conky/mountpoint/foo/bar', 'foo/bar'),
482                (r'\\conky\mountpoint\foo\bar', 'foo/bar'),
483                (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
484                (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
485                (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
486                (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
487                (r'//?/C:/foo/bar', 'foo/bar'),
488                (r'\\?\C:\foo\bar', 'foo/bar'),
489                (r'C:/../C:/foo/bar', 'C_/foo/bar'),
490                (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
491                ('../../foo../../ba..r', 'foo/ba..r'),
492            ])
493        else:  # Unix
494            hacknames.extend([
495                ('//foo/bar', 'foo/bar'),
496                ('../../foo../../ba..r', 'foo../ba..r'),
497                (r'foo/..\bar', r'foo/..\bar'),
498            ])
499
500        for arcname, fixedname in hacknames:
501            content = b'foobar' + arcname.encode()
502            with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
503                zinfo = zipfile.ZipInfo()
504                # preserve backslashes
505                zinfo.filename = arcname
506                zinfo.external_attr = 0o600 << 16
507                zipfp.writestr(zinfo, content)
508
509            arcname = arcname.replace(os.sep, "/")
510            targetpath = os.path.join('target', 'subdir', 'subsub')
511            correctfile = os.path.join(targetpath, *fixedname.split('/'))
512
513            with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
514                writtenfile = zipfp.extract(arcname, targetpath)
515                self.assertEqual(writtenfile, correctfile,
516                                 msg="extract %r" % arcname)
517            self.check_file(correctfile, content)
518            rmtree('target')
519
520            with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
521                zipfp.extractall(targetpath)
522            self.check_file(correctfile, content)
523            rmtree('target')
524
525            correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
526
527            with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
528                writtenfile = zipfp.extract(arcname)
529                self.assertEqual(writtenfile, correctfile,
530                                 msg="extract %r" % arcname)
531            self.check_file(correctfile, content)
532            rmtree(fixedname.split('/')[0])
533
534            with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
535                zipfp.extractall()
536            self.check_file(correctfile, content)
537            rmtree(fixedname.split('/')[0])
538
539            os.remove(TESTFN2)
540
541    def test_writestr_compression(self):
542        zipfp = zipfile.ZipFile(TESTFN2, "w")
543        zipfp.writestr("a.txt", "hello world", compress_type=zipfile.ZIP_STORED)
544        if zlib:
545            zipfp.writestr("b.txt", "hello world", compress_type=zipfile.ZIP_DEFLATED)
546
547        info = zipfp.getinfo('a.txt')
548        self.assertEqual(info.compress_type, zipfile.ZIP_STORED)
549
550        if zlib:
551            info = zipfp.getinfo('b.txt')
552            self.assertEqual(info.compress_type, zipfile.ZIP_DEFLATED)
553
554
555    def zip_test_writestr_permissions(self, f, compression):
556        # Make sure that writestr creates files with mode 0600,
557        # when it is passed a name rather than a ZipInfo instance.
558
559        self.make_test_archive(f, compression)
560        with zipfile.ZipFile(f, "r") as zipfp:
561            zinfo = zipfp.getinfo('strfile')
562            self.assertEqual(zinfo.external_attr, 0600 << 16)
563
564    def test_writestr_permissions(self):
565        for f in (TESTFN2, TemporaryFile(), StringIO()):
566            self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
567
568    def test_close(self):
569        """Check that the zipfile is closed after the 'with' block."""
570        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
571            for fpath, fdata in SMALL_TEST_DATA:
572                zipfp.writestr(fpath, fdata)
573                self.assertTrue(zipfp.fp is not None, 'zipfp is not open')
574        self.assertTrue(zipfp.fp is None, 'zipfp is not closed')
575
576        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
577            self.assertTrue(zipfp.fp is not None, 'zipfp is not open')
578        self.assertTrue(zipfp.fp is None, 'zipfp is not closed')
579
580    def test_close_on_exception(self):
581        """Check that the zipfile is closed if an exception is raised in the
582        'with' block."""
583        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
584            for fpath, fdata in SMALL_TEST_DATA:
585                zipfp.writestr(fpath, fdata)
586
587        try:
588            with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
589                raise zipfile.BadZipfile()
590        except zipfile.BadZipfile:
591            self.assertTrue(zipfp2.fp is None, 'zipfp is not closed')
592
593    def test_add_file_before_1980(self):
594        # Set atime and mtime to 1970-01-01
595        os.utime(TESTFN, (0, 0))
596        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
597            self.assertRaises(ValueError, zipfp.write, TESTFN)
598
599    def tearDown(self):
600        unlink(TESTFN)
601        unlink(TESTFN2)
602
603
604class TestZip64InSmallFiles(unittest.TestCase):
605    # These tests test the ZIP64 functionality without using large files,
606    # see test_zipfile64 for proper tests.
607
608    def setUp(self):
609        self._limit = zipfile.ZIP64_LIMIT
610        self._filecount_limit = zipfile.ZIP_FILECOUNT_LIMIT
611        zipfile.ZIP64_LIMIT = 1000
612        zipfile.ZIP_FILECOUNT_LIMIT = 9
613
614        line_gen = ("Test of zipfile line %d." % i
615                    for i in range(0, FIXEDTEST_SIZE))
616        self.data = '\n'.join(line_gen)
617
618        # Make a source file with some lines
619        with open(TESTFN, "wb") as fp:
620            fp.write(self.data)
621
622    def large_file_exception_test(self, f, compression):
623        with zipfile.ZipFile(f, "w", compression) as zipfp:
624            self.assertRaises(zipfile.LargeZipFile,
625                              zipfp.write, TESTFN, "another.name")
626
627    def large_file_exception_test2(self, f, compression):
628        with zipfile.ZipFile(f, "w", compression) as zipfp:
629            self.assertRaises(zipfile.LargeZipFile,
630                              zipfp.writestr, "another.name", self.data)
631
632    def test_large_file_exception(self):
633        for f in (TESTFN2, TemporaryFile(), StringIO()):
634            self.large_file_exception_test(f, zipfile.ZIP_STORED)
635            self.large_file_exception_test2(f, zipfile.ZIP_STORED)
636
637    def zip_test(self, f, compression):
638        # Create the ZIP archive
639        with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
640            zipfp.write(TESTFN, "another.name")
641            zipfp.write(TESTFN, TESTFN)
642            zipfp.writestr("strfile", self.data)
643
644        # Read the ZIP archive
645        with zipfile.ZipFile(f, "r", compression) as zipfp:
646            self.assertEqual(zipfp.read(TESTFN), self.data)
647            self.assertEqual(zipfp.read("another.name"), self.data)
648            self.assertEqual(zipfp.read("strfile"), self.data)
649
650            # Print the ZIP directory
651            fp = StringIO()
652            stdout = sys.stdout
653            try:
654                sys.stdout = fp
655                zipfp.printdir()
656            finally:
657                sys.stdout = stdout
658
659            directory = fp.getvalue()
660            lines = directory.splitlines()
661            self.assertEqual(len(lines), 4) # Number of files + header
662
663            self.assertIn('File Name', lines[0])
664            self.assertIn('Modified', lines[0])
665            self.assertIn('Size', lines[0])
666
667            fn, date, time_, size = lines[1].split()
668            self.assertEqual(fn, 'another.name')
669            self.assertTrue(time.strptime(date, '%Y-%m-%d'))
670            self.assertTrue(time.strptime(time_, '%H:%M:%S'))
671            self.assertEqual(size, str(len(self.data)))
672
673            # Check the namelist
674            names = zipfp.namelist()
675            self.assertEqual(len(names), 3)
676            self.assertIn(TESTFN, names)
677            self.assertIn("another.name", names)
678            self.assertIn("strfile", names)
679
680            # Check infolist
681            infos = zipfp.infolist()
682            names = [i.filename for i in infos]
683            self.assertEqual(len(names), 3)
684            self.assertIn(TESTFN, names)
685            self.assertIn("another.name", names)
686            self.assertIn("strfile", names)
687            for i in infos:
688                self.assertEqual(i.file_size, len(self.data))
689
690            # check getinfo
691            for nm in (TESTFN, "another.name", "strfile"):
692                info = zipfp.getinfo(nm)
693                self.assertEqual(info.filename, nm)
694                self.assertEqual(info.file_size, len(self.data))
695
696            # Check that testzip doesn't raise an exception
697            zipfp.testzip()
698
699    def test_stored(self):
700        for f in (TESTFN2, TemporaryFile(), StringIO()):
701            self.zip_test(f, zipfile.ZIP_STORED)
702
703    @skipUnless(zlib, "requires zlib")
704    def test_deflated(self):
705        for f in (TESTFN2, TemporaryFile(), StringIO()):
706            self.zip_test(f, zipfile.ZIP_DEFLATED)
707
708    def test_absolute_arcnames(self):
709        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
710                             allowZip64=True) as zipfp:
711            zipfp.write(TESTFN, "/absolute")
712
713        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
714            self.assertEqual(zipfp.namelist(), ["absolute"])
715
716    def test_too_many_files(self):
717        # This test checks that more than 64k files can be added to an archive,
718        # and that the resulting archive can be read properly by ZipFile
719        zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=True)
720        zipf.debug = 100
721        numfiles = 15
722        for i in range(numfiles):
723            zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
724        self.assertEqual(len(zipf.namelist()), numfiles)
725        zipf.close()
726
727        zipf2 = zipfile.ZipFile(TESTFN, mode="r")
728        self.assertEqual(len(zipf2.namelist()), numfiles)
729        for i in range(numfiles):
730            content = zipf2.read("foo%08d" % i)
731            self.assertEqual(content, "%d" % (i**3 % 57))
732        zipf2.close()
733
734    def test_too_many_files_append(self):
735        zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=False)
736        zipf.debug = 100
737        numfiles = 9
738        for i in range(numfiles):
739            zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
740        self.assertEqual(len(zipf.namelist()), numfiles)
741        with self.assertRaises(zipfile.LargeZipFile):
742            zipf.writestr("foo%08d" % numfiles, b'')
743        self.assertEqual(len(zipf.namelist()), numfiles)
744        zipf.close()
745
746        zipf = zipfile.ZipFile(TESTFN, mode="a", allowZip64=False)
747        zipf.debug = 100
748        self.assertEqual(len(zipf.namelist()), numfiles)
749        with self.assertRaises(zipfile.LargeZipFile):
750            zipf.writestr("foo%08d" % numfiles, b'')
751        self.assertEqual(len(zipf.namelist()), numfiles)
752        zipf.close()
753
754        zipf = zipfile.ZipFile(TESTFN, mode="a", allowZip64=True)
755        zipf.debug = 100
756        self.assertEqual(len(zipf.namelist()), numfiles)
757        numfiles2 = 15
758        for i in range(numfiles, numfiles2):
759            zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
760        self.assertEqual(len(zipf.namelist()), numfiles2)
761        zipf.close()
762
763        zipf2 = zipfile.ZipFile(TESTFN, mode="r")
764        self.assertEqual(len(zipf2.namelist()), numfiles2)
765        for i in range(numfiles2):
766            content = zipf2.read("foo%08d" % i)
767            self.assertEqual(content, "%d" % (i**3 % 57))
768        zipf2.close()
769
770    def tearDown(self):
771        zipfile.ZIP64_LIMIT = self._limit
772        zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit
773        unlink(TESTFN)
774        unlink(TESTFN2)
775
776
777class PyZipFileTests(unittest.TestCase):
778    def test_write_pyfile(self):
779        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
780            fn = __file__
781            if fn.endswith('.pyc') or fn.endswith('.pyo'):
782                fn = fn[:-1]
783
784            zipfp.writepy(fn)
785
786            bn = os.path.basename(fn)
787            self.assertNotIn(bn, zipfp.namelist())
788            self.assertTrue(bn + 'o' in zipfp.namelist() or
789                            bn + 'c' in zipfp.namelist())
790
791        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
792            fn = __file__
793            if fn.endswith(('.pyc', '.pyo')):
794                fn = fn[:-1]
795
796            zipfp.writepy(fn, "testpackage")
797
798            bn = "%s/%s" % ("testpackage", os.path.basename(fn))
799            self.assertNotIn(bn, zipfp.namelist())
800            self.assertTrue(bn + 'o' in zipfp.namelist() or
801                            bn + 'c' in zipfp.namelist())
802
803    def test_write_python_package(self):
804        import email
805        packagedir = os.path.dirname(email.__file__)
806
807        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
808            zipfp.writepy(packagedir)
809
810            # Check for a couple of modules at different levels of the
811            # hierarchy
812            names = zipfp.namelist()
813            self.assertTrue('email/__init__.pyo' in names or
814                            'email/__init__.pyc' in names)
815            self.assertTrue('email/mime/text.pyo' in names or
816                            'email/mime/text.pyc' in names)
817
818    def test_write_python_directory(self):
819        os.mkdir(TESTFN2)
820        try:
821            with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
822                fp.write("print(42)\n")
823
824            with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
825                fp.write("print(42 * 42)\n")
826
827            with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp:
828                fp.write("bla bla bla\n")
829
830            zipfp  = zipfile.PyZipFile(TemporaryFile(), "w")
831            zipfp.writepy(TESTFN2)
832
833            names = zipfp.namelist()
834            self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names)
835            self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names)
836            self.assertNotIn('mod2.txt', names)
837
838        finally:
839            rmtree(TESTFN2)
840
841    def test_write_non_pyfile(self):
842        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
843            with open(TESTFN, 'w') as fid:
844                fid.write('most definitely not a python file')
845            self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
846            os.remove(TESTFN)
847
848
849class OtherTests(unittest.TestCase):
850    zips_with_bad_crc = {
851        zipfile.ZIP_STORED: (
852            b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
853            b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
854            b'ilehello,AworldP'
855            b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
856            b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
857            b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
858            b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
859            b'\0\0/\0\0\0\0\0'),
860        zipfile.ZIP_DEFLATED: (
861            b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
862            b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
863            b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
864            b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
865            b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
866            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
867            b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
868            b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00'),
869    }
870
871    def test_unicode_filenames(self):
872        with zipfile.ZipFile(TESTFN, "w") as zf:
873            zf.writestr(u"foo.txt", "Test for unicode filename")
874            zf.writestr(u"\xf6.txt", "Test for unicode filename")
875            self.assertIsInstance(zf.infolist()[0].filename, unicode)
876
877        with zipfile.ZipFile(TESTFN, "r") as zf:
878            self.assertEqual(zf.filelist[0].filename, "foo.txt")
879            self.assertEqual(zf.filelist[1].filename, u"\xf6.txt")
880
881    def test_create_non_existent_file_for_append(self):
882        if os.path.exists(TESTFN):
883            os.unlink(TESTFN)
884
885        filename = 'testfile.txt'
886        content = 'hello, world. this is some content.'
887
888        try:
889            with zipfile.ZipFile(TESTFN, 'a') as zf:
890                zf.writestr(filename, content)
891        except IOError:
892            self.fail('Could not append data to a non-existent zip file.')
893
894        self.assertTrue(os.path.exists(TESTFN))
895
896        with zipfile.ZipFile(TESTFN, 'r') as zf:
897            self.assertEqual(zf.read(filename), content)
898
899    def test_close_erroneous_file(self):
900        # This test checks that the ZipFile constructor closes the file object
901        # it opens if there's an error in the file.  If it doesn't, the
902        # traceback holds a reference to the ZipFile object and, indirectly,
903        # the file object.
904        # On Windows, this causes the os.unlink() call to fail because the
905        # underlying file is still open.  This is SF bug #412214.
906        #
907        with open(TESTFN, "w") as fp:
908            fp.write("this is not a legal zip file\n")
909        try:
910            zf = zipfile.ZipFile(TESTFN)
911        except zipfile.BadZipfile:
912            pass
913
914    def test_is_zip_erroneous_file(self):
915        """Check that is_zipfile() correctly identifies non-zip files."""
916        # - passing a filename
917        with open(TESTFN, "w") as fp:
918            fp.write("this is not a legal zip file\n")
919        chk = zipfile.is_zipfile(TESTFN)
920        self.assertFalse(chk)
921        # - passing a file object
922        with open(TESTFN, "rb") as fp:
923            chk = zipfile.is_zipfile(fp)
924            self.assertTrue(not chk)
925        # - passing a file-like object
926        fp = StringIO()
927        fp.write("this is not a legal zip file\n")
928        chk = zipfile.is_zipfile(fp)
929        self.assertTrue(not chk)
930        fp.seek(0, 0)
931        chk = zipfile.is_zipfile(fp)
932        self.assertTrue(not chk)
933
934    def test_damaged_zipfile(self):
935        """Check that zipfiles with missing bytes at the end raise BadZipFile."""
936        # - Create a valid zip file
937        fp = io.BytesIO()
938        with zipfile.ZipFile(fp, mode="w") as zipf:
939            zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
940        zipfiledata = fp.getvalue()
941
942        # - Now create copies of it missing the last N bytes and make sure
943        #   a BadZipFile exception is raised when we try to open it
944        for N in range(len(zipfiledata)):
945            fp = io.BytesIO(zipfiledata[:N])
946            self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, fp)
947
948    def test_is_zip_valid_file(self):
949        """Check that is_zipfile() correctly identifies zip files."""
950        # - passing a filename
951        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
952            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
953        chk = zipfile.is_zipfile(TESTFN)
954        self.assertTrue(chk)
955        # - passing a file object
956        with open(TESTFN, "rb") as fp:
957            chk = zipfile.is_zipfile(fp)
958            self.assertTrue(chk)
959            fp.seek(0, 0)
960            zip_contents = fp.read()
961        # - passing a file-like object
962        fp = StringIO()
963        fp.write(zip_contents)
964        chk = zipfile.is_zipfile(fp)
965        self.assertTrue(chk)
966        fp.seek(0, 0)
967        chk = zipfile.is_zipfile(fp)
968        self.assertTrue(chk)
969
970    def test_non_existent_file_raises_IOError(self):
971        # make sure we don't raise an AttributeError when a partially-constructed
972        # ZipFile instance is finalized; this tests for regression on SF tracker
973        # bug #403871.
974
975        # The bug we're testing for caused an AttributeError to be raised
976        # when a ZipFile instance was created for a file that did not
977        # exist; the .fp member was not initialized but was needed by the
978        # __del__() method.  Since the AttributeError is in the __del__(),
979        # it is ignored, but the user should be sufficiently annoyed by
980        # the message on the output that regression will be noticed
981        # quickly.
982        self.assertRaises(IOError, zipfile.ZipFile, TESTFN)
983
984    def test_empty_file_raises_BadZipFile(self):
985        with open(TESTFN, 'w') as f:
986            pass
987        self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN)
988
989        with open(TESTFN, 'w') as fp:
990            fp.write("short file")
991        self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN)
992
993    def test_closed_zip_raises_RuntimeError(self):
994        """Verify that testzip() doesn't swallow inappropriate exceptions."""
995        data = StringIO()
996        with zipfile.ZipFile(data, mode="w") as zipf:
997            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
998
999        # This is correct; calling .read on a closed ZipFile should raise
1000        # a RuntimeError, and so should calling .testzip.  An earlier
1001        # version of .testzip would swallow this exception (and any other)
1002        # and report that the first file in the archive was corrupt.
1003        self.assertRaises(RuntimeError, zipf.read, "foo.txt")
1004        self.assertRaises(RuntimeError, zipf.open, "foo.txt")
1005        self.assertRaises(RuntimeError, zipf.testzip)
1006        self.assertRaises(RuntimeError, zipf.writestr, "bogus.txt", "bogus")
1007        with open(TESTFN, 'w') as fid:
1008            fid.write('zipfile test data')
1009            self.assertRaises(RuntimeError, zipf.write, TESTFN)
1010
1011    def test_bad_constructor_mode(self):
1012        """Check that bad modes passed to ZipFile constructor are caught."""
1013        self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "q")
1014
1015    def test_bad_open_mode(self):
1016        """Check that bad modes passed to ZipFile.open are caught."""
1017        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1018            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1019
1020        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
1021        # read the data to make sure the file is there
1022            zipf.read("foo.txt")
1023            self.assertRaises(RuntimeError, zipf.open, "foo.txt", "q")
1024
1025    def test_read0(self):
1026        """Check that calling read(0) on a ZipExtFile object returns an empty
1027        string and doesn't advance file pointer."""
1028        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1029            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1030            # read the data to make sure the file is there
1031            with zipf.open("foo.txt") as f:
1032                for i in xrange(FIXEDTEST_SIZE):
1033                    self.assertEqual(f.read(0), '')
1034
1035                self.assertEqual(f.read(), "O, for a Muse of Fire!")
1036
1037    def test_open_non_existent_item(self):
1038        """Check that attempting to call open() for an item that doesn't
1039        exist in the archive raises a RuntimeError."""
1040        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1041            self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
1042
1043    def test_bad_compression_mode(self):
1044        """Check that bad compression methods passed to ZipFile.open are
1045        caught."""
1046        self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "w", -1)
1047
1048    def test_unsupported_compression(self):
1049        # data is declared as shrunk, but actually deflated
1050        data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
1051        b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
1052        b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
1053        b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1054        b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
1055        b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
1056        with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
1057            self.assertRaises(NotImplementedError, zipf.open, 'x')
1058
1059    def test_null_byte_in_filename(self):
1060        """Check that a filename containing a null byte is properly
1061        terminated."""
1062        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1063            zipf.writestr("foo.txt\x00qqq", "O, for a Muse of Fire!")
1064            self.assertEqual(zipf.namelist(), ['foo.txt'])
1065
1066    def test_struct_sizes(self):
1067        """Check that ZIP internal structure sizes are calculated correctly."""
1068        self.assertEqual(zipfile.sizeEndCentDir, 22)
1069        self.assertEqual(zipfile.sizeCentralDir, 46)
1070        self.assertEqual(zipfile.sizeEndCentDir64, 56)
1071        self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
1072
1073    def test_comments(self):
1074        """Check that comments on the archive are handled properly."""
1075
1076        # check default comment is empty
1077        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1078            self.assertEqual(zipf.comment, '')
1079            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1080
1081        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
1082            self.assertEqual(zipf.comment, '')
1083
1084        # check a simple short comment
1085        comment = 'Bravely taking to his feet, he beat a very brave retreat.'
1086        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1087            zipf.comment = comment
1088            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1089        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
1090            self.assertEqual(zipf.comment, comment)
1091
1092        # check a comment of max length
1093        comment2 = ''.join(['%d' % (i**3 % 10) for i in xrange((1 << 16)-1)])
1094        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1095            zipf.comment = comment2
1096            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1097
1098        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
1099            self.assertEqual(zipf.comment, comment2)
1100
1101        # check a comment that is too long is truncated
1102        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1103            with check_warnings(('', UserWarning)):
1104                zipf.comment = comment2 + 'oops'
1105            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1106        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
1107            self.assertEqual(zipf.comment, comment2)
1108
1109    def test_change_comment_in_empty_archive(self):
1110        with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1111            self.assertFalse(zipf.filelist)
1112            zipf.comment = b"this is a comment"
1113        with zipfile.ZipFile(TESTFN, "r") as zipf:
1114            self.assertEqual(zipf.comment, b"this is a comment")
1115
1116    def test_change_comment_in_nonempty_archive(self):
1117        with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1118            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1119        with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1120            self.assertTrue(zipf.filelist)
1121            zipf.comment = b"this is a comment"
1122        with zipfile.ZipFile(TESTFN, "r") as zipf:
1123            self.assertEqual(zipf.comment, b"this is a comment")
1124
1125    def check_testzip_with_bad_crc(self, compression):
1126        """Tests that files with bad CRCs return their name from testzip."""
1127        zipdata = self.zips_with_bad_crc[compression]
1128
1129        with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1130            # testzip returns the name of the first corrupt file, or None
1131            self.assertEqual('afile', zipf.testzip())
1132
1133    def test_testzip_with_bad_crc_stored(self):
1134        self.check_testzip_with_bad_crc(zipfile.ZIP_STORED)
1135
1136    @skipUnless(zlib, "requires zlib")
1137    def test_testzip_with_bad_crc_deflated(self):
1138        self.check_testzip_with_bad_crc(zipfile.ZIP_DEFLATED)
1139
1140    def check_read_with_bad_crc(self, compression):
1141        """Tests that files with bad CRCs raise a BadZipfile exception when read."""
1142        zipdata = self.zips_with_bad_crc[compression]
1143
1144        # Using ZipFile.read()
1145        with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1146            self.assertRaises(zipfile.BadZipfile, zipf.read, 'afile')
1147
1148        # Using ZipExtFile.read()
1149        with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1150            with zipf.open('afile', 'r') as corrupt_file:
1151                self.assertRaises(zipfile.BadZipfile, corrupt_file.read)
1152
1153        # Same with small reads (in order to exercise the buffering logic)
1154        with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
1155            with zipf.open('afile', 'r') as corrupt_file:
1156                corrupt_file.MIN_READ_SIZE = 2
1157                with self.assertRaises(zipfile.BadZipfile):
1158                    while corrupt_file.read(2):
1159                        pass
1160
1161    def test_read_with_bad_crc_stored(self):
1162        self.check_read_with_bad_crc(zipfile.ZIP_STORED)
1163
1164    @skipUnless(zlib, "requires zlib")
1165    def test_read_with_bad_crc_deflated(self):
1166        self.check_read_with_bad_crc(zipfile.ZIP_DEFLATED)
1167
1168    def check_read_return_size(self, compression):
1169        # Issue #9837: ZipExtFile.read() shouldn't return more bytes
1170        # than requested.
1171        for test_size in (1, 4095, 4096, 4097, 16384):
1172            file_size = test_size + 1
1173            junk = getrandbytes(file_size)
1174            with zipfile.ZipFile(io.BytesIO(), "w", compression) as zipf:
1175                zipf.writestr('foo', junk)
1176                with zipf.open('foo', 'r') as fp:
1177                    buf = fp.read(test_size)
1178                    self.assertEqual(len(buf), test_size)
1179
1180    def test_read_return_size_stored(self):
1181        self.check_read_return_size(zipfile.ZIP_STORED)
1182
1183    @skipUnless(zlib, "requires zlib")
1184    def test_read_return_size_deflated(self):
1185        self.check_read_return_size(zipfile.ZIP_DEFLATED)
1186
1187    def test_empty_zipfile(self):
1188        # Check that creating a file in 'w' or 'a' mode and closing without
1189        # adding any files to the archives creates a valid empty ZIP file
1190        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1191            pass
1192        try:
1193            zipf = zipfile.ZipFile(TESTFN, mode="r")
1194            zipf.close()
1195        except zipfile.BadZipfile:
1196            self.fail("Unable to create empty ZIP file in 'w' mode")
1197
1198        with zipfile.ZipFile(TESTFN, mode="a") as zipf:
1199            pass
1200        try:
1201            zipf = zipfile.ZipFile(TESTFN, mode="r")
1202            zipf.close()
1203        except:
1204            self.fail("Unable to create empty ZIP file in 'a' mode")
1205
1206    def test_open_empty_file(self):
1207        # Issue 1710703: Check that opening a file with less than 22 bytes
1208        # raises a BadZipfile exception (rather than the previously unhelpful
1209        # IOError)
1210        with open(TESTFN, 'w') as f:
1211            pass
1212        self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN, 'r')
1213
1214    def test_create_zipinfo_before_1980(self):
1215        self.assertRaises(ValueError,
1216                          zipfile.ZipInfo, 'seventies', (1979, 1, 1, 0, 0, 0))
1217
1218    def test_zipfile_with_short_extra_field(self):
1219        """If an extra field in the header is less than 4 bytes, skip it."""
1220        zipdata = (
1221            b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1222            b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1223            b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1224            b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1225            b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1226            b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1227            b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1228        )
1229        with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1230            # testzip returns the name of the first corrupt file, or None
1231            self.assertIsNone(zipf.testzip())
1232
1233    def tearDown(self):
1234        unlink(TESTFN)
1235        unlink(TESTFN2)
1236
1237
1238class DecryptionTests(unittest.TestCase):
1239    """Check that ZIP decryption works. Since the library does not
1240    support encryption at the moment, we use a pre-generated encrypted
1241    ZIP file."""
1242
1243    data = (
1244    'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
1245    '\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
1246    '\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
1247    'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
1248    '\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
1249    '\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
1250    '\x00\x00L\x00\x00\x00\x00\x00' )
1251    data2 = (
1252    'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
1253    '\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
1254    '\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
1255    'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
1256    '\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
1257    '\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
1258    'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
1259    '\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
1260
1261    plain = 'zipfile.py encryption test'
1262    plain2 = '\x00'*512
1263
1264    def setUp(self):
1265        with open(TESTFN, "wb") as fp:
1266            fp.write(self.data)
1267        self.zip = zipfile.ZipFile(TESTFN, "r")
1268        with open(TESTFN2, "wb") as fp:
1269            fp.write(self.data2)
1270        self.zip2 = zipfile.ZipFile(TESTFN2, "r")
1271
1272    def tearDown(self):
1273        self.zip.close()
1274        os.unlink(TESTFN)
1275        self.zip2.close()
1276        os.unlink(TESTFN2)
1277
1278    def test_no_password(self):
1279        # Reading the encrypted file without password
1280        # must generate a RunTime exception
1281        self.assertRaises(RuntimeError, self.zip.read, "test.txt")
1282        self.assertRaises(RuntimeError, self.zip2.read, "zero")
1283
1284    def test_bad_password(self):
1285        self.zip.setpassword("perl")
1286        self.assertRaises(RuntimeError, self.zip.read, "test.txt")
1287        self.zip2.setpassword("perl")
1288        self.assertRaises(RuntimeError, self.zip2.read, "zero")
1289
1290    @skipUnless(zlib, "requires zlib")
1291    def test_good_password(self):
1292        self.zip.setpassword("python")
1293        self.assertEqual(self.zip.read("test.txt"), self.plain)
1294        self.zip2.setpassword("12345")
1295        self.assertEqual(self.zip2.read("zero"), self.plain2)
1296
1297
1298class TestsWithRandomBinaryFiles(unittest.TestCase):
1299    def setUp(self):
1300        datacount = randint(16, 64)*1024 + randint(1, 1024)
1301        self.data = ''.join(struct.pack('<f', random()*randint(-1000, 1000))
1302                            for i in xrange(datacount))
1303
1304        # Make a source file with some lines
1305        with open(TESTFN, "wb") as fp:
1306            fp.write(self.data)
1307
1308    def tearDown(self):
1309        unlink(TESTFN)
1310        unlink(TESTFN2)
1311
1312    def make_test_archive(self, f, compression):
1313        # Create the ZIP archive
1314        with zipfile.ZipFile(f, "w", compression) as zipfp:
1315            zipfp.write(TESTFN, "another.name")
1316            zipfp.write(TESTFN, TESTFN)
1317
1318    def zip_test(self, f, compression):
1319        self.make_test_archive(f, compression)
1320
1321        # Read the ZIP archive
1322        with zipfile.ZipFile(f, "r", compression) as zipfp:
1323            testdata = zipfp.read(TESTFN)
1324            self.assertEqual(len(testdata), len(self.data))
1325            self.assertEqual(testdata, self.data)
1326            self.assertEqual(zipfp.read("another.name"), self.data)
1327
1328    def test_stored(self):
1329        for f in (TESTFN2, TemporaryFile(), StringIO()):
1330            self.zip_test(f, zipfile.ZIP_STORED)
1331
1332    @skipUnless(zlib, "requires zlib")
1333    def test_deflated(self):
1334        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
1335            self.zip_test(f, zipfile.ZIP_DEFLATED)
1336
1337    def zip_open_test(self, f, compression):
1338        self.make_test_archive(f, compression)
1339
1340        # Read the ZIP archive
1341        with zipfile.ZipFile(f, "r", compression) as zipfp:
1342            zipdata1 = []
1343            with zipfp.open(TESTFN) as zipopen1:
1344                while True:
1345                    read_data = zipopen1.read(256)
1346                    if not read_data:
1347                        break
1348                    zipdata1.append(read_data)
1349
1350            zipdata2 = []
1351            with zipfp.open("another.name") as zipopen2:
1352                while True:
1353                    read_data = zipopen2.read(256)
1354                    if not read_data:
1355                        break
1356                    zipdata2.append(read_data)
1357
1358            testdata1 = ''.join(zipdata1)
1359            self.assertEqual(len(testdata1), len(self.data))
1360            self.assertEqual(testdata1, self.data)
1361
1362            testdata2 = ''.join(zipdata2)
1363            self.assertEqual(len(testdata2), len(self.data))
1364            self.assertEqual(testdata2, self.data)
1365
1366    def test_open_stored(self):
1367        for f in (TESTFN2, TemporaryFile(), StringIO()):
1368            self.zip_open_test(f, zipfile.ZIP_STORED)
1369
1370    @skipUnless(zlib, "requires zlib")
1371    def test_open_deflated(self):
1372        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
1373            self.zip_open_test(f, zipfile.ZIP_DEFLATED)
1374
1375    def zip_random_open_test(self, f, compression):
1376        self.make_test_archive(f, compression)
1377
1378        # Read the ZIP archive
1379        with zipfile.ZipFile(f, "r", compression) as zipfp:
1380            zipdata1 = []
1381            with zipfp.open(TESTFN) as zipopen1:
1382                while True:
1383                    read_data = zipopen1.read(randint(1, 1024))
1384                    if not read_data:
1385                        break
1386                    zipdata1.append(read_data)
1387
1388            testdata = ''.join(zipdata1)
1389            self.assertEqual(len(testdata), len(self.data))
1390            self.assertEqual(testdata, self.data)
1391
1392    def test_random_open_stored(self):
1393        for f in (TESTFN2, TemporaryFile(), StringIO()):
1394            self.zip_random_open_test(f, zipfile.ZIP_STORED)
1395
1396    @skipUnless(zlib, "requires zlib")
1397    def test_random_open_deflated(self):
1398        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
1399            self.zip_random_open_test(f, zipfile.ZIP_DEFLATED)
1400
1401
1402@skipUnless(zlib, "requires zlib")
1403class TestsWithMultipleOpens(unittest.TestCase):
1404    @classmethod
1405    def setUpClass(cls):
1406        cls.data1 = b'111' + getrandbytes(10000)
1407        cls.data2 = b'222' + getrandbytes(10000)
1408
1409    def make_test_archive(self, f):
1410        # Create the ZIP archive
1411        with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
1412            zipfp.writestr('ones', self.data1)
1413            zipfp.writestr('twos', self.data2)
1414
1415    def test_same_file(self):
1416        # Verify that (when the ZipFile is in control of creating file objects)
1417        # multiple open() calls can be made without interfering with each other.
1418        self.make_test_archive(TESTFN2)
1419        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
1420            with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
1421                data1 = zopen1.read(500)
1422                data2 = zopen2.read(500)
1423                data1 += zopen1.read()
1424                data2 += zopen2.read()
1425            self.assertEqual(data1, data2)
1426            self.assertEqual(data1, self.data1)
1427
1428    def test_different_file(self):
1429        # Verify that (when the ZipFile is in control of creating file objects)
1430        # multiple open() calls can be made without interfering with each other.
1431        self.make_test_archive(TESTFN2)
1432        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
1433            with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
1434                data1 = zopen1.read(500)
1435                data2 = zopen2.read(500)
1436                data1 += zopen1.read()
1437                data2 += zopen2.read()
1438            self.assertEqual(data1, self.data1)
1439            self.assertEqual(data2, self.data2)
1440
1441    def test_interleaved(self):
1442        # Verify that (when the ZipFile is in control of creating file objects)
1443        # multiple open() calls can be made without interfering with each other.
1444        self.make_test_archive(TESTFN2)
1445        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
1446            with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
1447                data1 = zopen1.read(500)
1448                data2 = zopen2.read(500)
1449                data1 += zopen1.read()
1450                data2 += zopen2.read()
1451            self.assertEqual(data1, self.data1)
1452            self.assertEqual(data2, self.data2)
1453
1454    def test_read_after_close(self):
1455        self.make_test_archive(TESTFN2)
1456        zopen1 = zopen2 = None
1457        try:
1458            with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1459                zopen1 = zipf.open('ones')
1460                zopen2 = zipf.open('twos')
1461            data1 = zopen1.read(500)
1462            data2 = zopen2.read(500)
1463            data1 += zopen1.read()
1464            data2 += zopen2.read()
1465        finally:
1466            if zopen1:
1467                zopen1.close()
1468            if zopen2:
1469                zopen2.close()
1470        self.assertEqual(data1, self.data1)
1471        self.assertEqual(data2, self.data2)
1472
1473    def test_read_after_write(self):
1474        with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
1475            zipf.writestr('ones', self.data1)
1476            zipf.writestr('twos', self.data2)
1477            with zipf.open('ones') as zopen1:
1478                data1 = zopen1.read(500)
1479        self.assertEqual(data1, self.data1[:500])
1480        with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1481            data1 = zipf.read('ones')
1482            data2 = zipf.read('twos')
1483        self.assertEqual(data1, self.data1)
1484        self.assertEqual(data2, self.data2)
1485
1486    def test_write_after_read(self):
1487        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipf:
1488            zipf.writestr('ones', self.data1)
1489            with zipf.open('ones') as zopen1:
1490                zopen1.read(500)
1491                zipf.writestr('twos', self.data2)
1492        with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1493            data1 = zipf.read('ones')
1494            data2 = zipf.read('twos')
1495        self.assertEqual(data1, self.data1)
1496        self.assertEqual(data2, self.data2)
1497
1498    def test_many_opens(self):
1499        # Verify that read() and open() promptly close the file descriptor,
1500        # and don't rely on the garbage collector to free resources.
1501        self.make_test_archive(TESTFN2)
1502        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
1503            for x in range(100):
1504                zipf.read('ones')
1505                with zipf.open('ones') as zopen1:
1506                    pass
1507        with open(os.devnull) as f:
1508            self.assertLess(f.fileno(), 100)
1509
1510    def tearDown(self):
1511        unlink(TESTFN2)
1512
1513
1514class TestWithDirectory(unittest.TestCase):
1515    def setUp(self):
1516        os.mkdir(TESTFN2)
1517
1518    def test_extract_dir(self):
1519        with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
1520            zipf.extractall(TESTFN2)
1521        self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
1522        self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
1523        self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
1524
1525    def test_bug_6050(self):
1526        # Extraction should succeed if directories already exist
1527        os.mkdir(os.path.join(TESTFN2, "a"))
1528        self.test_extract_dir()
1529
1530    def test_write_dir(self):
1531        dirpath = os.path.join(TESTFN2, "x")
1532        os.mkdir(dirpath)
1533        mode = os.stat(dirpath).st_mode & 0xFFFF
1534        with zipfile.ZipFile(TESTFN, "w") as zipf:
1535            zipf.write(dirpath)
1536            zinfo = zipf.filelist[0]
1537            self.assertTrue(zinfo.filename.endswith("/x/"))
1538            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
1539            zipf.write(dirpath, "y")
1540            zinfo = zipf.filelist[1]
1541            self.assertTrue(zinfo.filename, "y/")
1542            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
1543        with zipfile.ZipFile(TESTFN, "r") as zipf:
1544            zinfo = zipf.filelist[0]
1545            self.assertTrue(zinfo.filename.endswith("/x/"))
1546            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
1547            zinfo = zipf.filelist[1]
1548            self.assertTrue(zinfo.filename, "y/")
1549            self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
1550            target = os.path.join(TESTFN2, "target")
1551            os.mkdir(target)
1552            zipf.extractall(target)
1553            self.assertTrue(os.path.isdir(os.path.join(target, "y")))
1554            self.assertEqual(len(os.listdir(target)), 2)
1555
1556    def test_writestr_dir(self):
1557        os.mkdir(os.path.join(TESTFN2, "x"))
1558        with zipfile.ZipFile(TESTFN, "w") as zipf:
1559            zipf.writestr("x/", b'')
1560            zinfo = zipf.filelist[0]
1561            self.assertEqual(zinfo.filename, "x/")
1562            self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
1563        with zipfile.ZipFile(TESTFN, "r") as zipf:
1564            zinfo = zipf.filelist[0]
1565            self.assertTrue(zinfo.filename.endswith("x/"))
1566            self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
1567            target = os.path.join(TESTFN2, "target")
1568            os.mkdir(target)
1569            zipf.extractall(target)
1570            self.assertTrue(os.path.isdir(os.path.join(target, "x")))
1571            self.assertEqual(os.listdir(target), ["x"])
1572
1573    def tearDown(self):
1574        rmtree(TESTFN2)
1575        if os.path.exists(TESTFN):
1576            unlink(TESTFN)
1577
1578
1579class UniversalNewlineTests(unittest.TestCase):
1580    def setUp(self):
1581        self.line_gen = ["Test of zipfile line %d." % i
1582                         for i in xrange(FIXEDTEST_SIZE)]
1583        self.seps = ('\r', '\r\n', '\n')
1584        self.arcdata, self.arcfiles = {}, {}
1585        for n, s in enumerate(self.seps):
1586            self.arcdata[s] = s.join(self.line_gen) + s
1587            self.arcfiles[s] = '%s-%d' % (TESTFN, n)
1588            with open(self.arcfiles[s], "wb") as fid:
1589                fid.write(self.arcdata[s])
1590
1591    def make_test_archive(self, f, compression):
1592        # Create the ZIP archive
1593        with zipfile.ZipFile(f, "w", compression) as zipfp:
1594            for fn in self.arcfiles.values():
1595                zipfp.write(fn, fn)
1596
1597    def read_test(self, f, compression):
1598        self.make_test_archive(f, compression)
1599
1600        # Read the ZIP archive
1601        with zipfile.ZipFile(f, "r") as zipfp:
1602            for sep, fn in self.arcfiles.items():
1603                with zipfp.open(fn, "rU") as fp:
1604                    zipdata = fp.read()
1605                self.assertEqual(self.arcdata[sep], zipdata)
1606
1607    def readline_read_test(self, f, compression):
1608        self.make_test_archive(f, compression)
1609
1610        # Read the ZIP archive
1611        zipfp = zipfile.ZipFile(f, "r")
1612        for sep, fn in self.arcfiles.items():
1613            with zipfp.open(fn, "rU") as zipopen:
1614                data = ''
1615                while True:
1616                    read = zipopen.readline()
1617                    if not read:
1618                        break
1619                    data += read
1620
1621                    read = zipopen.read(5)
1622                    if not read:
1623                        break
1624                    data += read
1625
1626            self.assertEqual(data, self.arcdata['\n'])
1627
1628        zipfp.close()
1629
1630    def readline_test(self, f, compression):
1631        self.make_test_archive(f, compression)
1632
1633        # Read the ZIP archive
1634        with zipfile.ZipFile(f, "r") as zipfp:
1635            for sep, fn in self.arcfiles.items():
1636                with zipfp.open(fn, "rU") as zipopen:
1637                    for line in self.line_gen:
1638                        linedata = zipopen.readline()
1639                        self.assertEqual(linedata, line + '\n')
1640
1641    def readlines_test(self, f, compression):
1642        self.make_test_archive(f, compression)
1643
1644        # Read the ZIP archive
1645        with zipfile.ZipFile(f, "r") as zipfp:
1646            for sep, fn in self.arcfiles.items():
1647                with zipfp.open(fn, "rU") as fp:
1648                    ziplines = fp.readlines()
1649                for line, zipline in zip(self.line_gen, ziplines):
1650                    self.assertEqual(zipline, line + '\n')
1651
1652    def iterlines_test(self, f, compression):
1653        self.make_test_archive(f, compression)
1654
1655        # Read the ZIP archive
1656        with zipfile.ZipFile(f, "r") as zipfp:
1657            for sep, fn in self.arcfiles.items():
1658                with zipfp.open(fn, "rU") as fid:
1659                    for line, zipline in zip(self.line_gen, fid):
1660                        self.assertEqual(zipline, line + '\n')
1661
1662    def test_read_stored(self):
1663        for f in (TESTFN2, TemporaryFile(), StringIO()):
1664            self.read_test(f, zipfile.ZIP_STORED)
1665
1666    def test_readline_read_stored(self):
1667        # Issue #7610: calls to readline() interleaved with calls to read().
1668        for f in (TESTFN2, TemporaryFile(), StringIO()):
1669            self.readline_read_test(f, zipfile.ZIP_STORED)
1670
1671    def test_readline_stored(self):
1672        for f in (TESTFN2, TemporaryFile(), StringIO()):
1673            self.readline_test(f, zipfile.ZIP_STORED)
1674
1675    def test_readlines_stored(self):
1676        for f in (TESTFN2, TemporaryFile(), StringIO()):
1677            self.readlines_test(f, zipfile.ZIP_STORED)
1678
1679    def test_iterlines_stored(self):
1680        for f in (TESTFN2, TemporaryFile(), StringIO()):
1681            self.iterlines_test(f, zipfile.ZIP_STORED)
1682
1683    @skipUnless(zlib, "requires zlib")
1684    def test_read_deflated(self):
1685        for f in (TESTFN2, TemporaryFile(), StringIO()):
1686            self.read_test(f, zipfile.ZIP_DEFLATED)
1687
1688    @skipUnless(zlib, "requires zlib")
1689    def test_readline_read_deflated(self):
1690        # Issue #7610: calls to readline() interleaved with calls to read().
1691        for f in (TESTFN2, TemporaryFile(), StringIO()):
1692            self.readline_read_test(f, zipfile.ZIP_DEFLATED)
1693
1694    @skipUnless(zlib, "requires zlib")
1695    def test_readline_deflated(self):
1696        for f in (TESTFN2, TemporaryFile(), StringIO()):
1697            self.readline_test(f, zipfile.ZIP_DEFLATED)
1698
1699    @skipUnless(zlib, "requires zlib")
1700    def test_readlines_deflated(self):
1701        for f in (TESTFN2, TemporaryFile(), StringIO()):
1702            self.readlines_test(f, zipfile.ZIP_DEFLATED)
1703
1704    @skipUnless(zlib, "requires zlib")
1705    def test_iterlines_deflated(self):
1706        for f in (TESTFN2, TemporaryFile(), StringIO()):
1707            self.iterlines_test(f, zipfile.ZIP_DEFLATED)
1708
1709    def tearDown(self):
1710        for sep, fn in self.arcfiles.items():
1711            os.remove(fn)
1712        unlink(TESTFN)
1713        unlink(TESTFN2)
1714
1715
1716def test_main():
1717    run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests,
1718                 PyZipFileTests, DecryptionTests, TestsWithMultipleOpens,
1719                 TestWithDirectory, UniversalNewlineTests,
1720                 TestsWithRandomBinaryFiles)
1721
1722if __name__ == "__main__":
1723    test_main()
1724