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