test_zipfile.py revision 569e61f35196cb765eb9940f75b27bb765e73073
1# We can test part of the module without zlib.
2try:
3    import zlib
4except ImportError:
5    zlib = None
6
7import os
8import sys
9import shutil
10import struct
11import zipfile
12import unittest
13
14from StringIO import StringIO
15from tempfile import TemporaryFile
16from random import randint, random
17from unittest import skipUnless
18
19from test.test_support import TESTFN, run_unittest, findfile, unlink
20
21TESTFN2 = TESTFN + "2"
22TESTFNDIR = TESTFN + "d"
23FIXEDTEST_SIZE = 1000
24
25SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
26                   ('ziptest2dir/_ziptest2', 'qawsedrftg'),
27                   ('/ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
28                   ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')]
29
30
31class TestsWithSourceFile(unittest.TestCase):
32    def setUp(self):
33        self.line_gen = ["Zipfile test line %d. random float: %f" % (i, random())
34                          for i in xrange(FIXEDTEST_SIZE)]
35        self.data = '\n'.join(self.line_gen) + '\n'
36
37        # Make a source file with some lines
38        fp = open(TESTFN, "wb")
39        fp.write(self.data)
40        fp.close()
41
42    def make_test_archive(self, f, compression):
43        # Create the ZIP archive
44        with zipfile.ZipFile(f, "w", compression) as zipfp:
45            zipfp.write(TESTFN, "another"+os.extsep+"name")
46            zipfp.write(TESTFN, TESTFN)
47            zipfp.writestr("strfile", self.data)
48
49    def zip_test(self, f, compression):
50        self.make_test_archive(f, compression)
51
52        # Read the ZIP archive
53        with zipfile.ZipFile(f, "r", compression) as zipfp:
54            self.assertEqual(zipfp.read(TESTFN), self.data)
55            self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
56            self.assertEqual(zipfp.read("strfile"), self.data)
57
58            # Print the ZIP directory
59            fp = StringIO()
60            stdout = sys.stdout
61            try:
62                sys.stdout = fp
63                zipfp.printdir()
64            finally:
65                sys.stdout = stdout
66
67            directory = fp.getvalue()
68            lines = directory.splitlines()
69            self.assertEquals(len(lines), 4) # Number of files + header
70
71            self.assertTrue('File Name' in lines[0])
72            self.assertTrue('Modified' in lines[0])
73            self.assertTrue('Size' in lines[0])
74
75            fn, date, time, size = lines[1].split()
76            self.assertEquals(fn, 'another.name')
77            # XXX: timestamp is not tested
78            self.assertEquals(size, str(len(self.data)))
79
80            # Check the namelist
81            names = zipfp.namelist()
82            self.assertEquals(len(names), 3)
83            self.assertTrue(TESTFN in names)
84            self.assertTrue("another"+os.extsep+"name" in names)
85            self.assertTrue("strfile" in names)
86
87            # Check infolist
88            infos = zipfp.infolist()
89            names = [ i.filename for i in infos ]
90            self.assertEquals(len(names), 3)
91            self.assertTrue(TESTFN in names)
92            self.assertTrue("another"+os.extsep+"name" in names)
93            self.assertTrue("strfile" in names)
94            for i in infos:
95                self.assertEquals(i.file_size, len(self.data))
96
97            # check getinfo
98            for nm in (TESTFN, "another"+os.extsep+"name", "strfile"):
99                info = zipfp.getinfo(nm)
100                self.assertEquals(info.filename, nm)
101                self.assertEquals(info.file_size, len(self.data))
102
103            # Check that testzip doesn't raise an exception
104            zipfp.testzip()
105
106    def test_stored(self):
107        for f in (TESTFN2, TemporaryFile(), StringIO()):
108            self.zip_test(f, zipfile.ZIP_STORED)
109
110    def zip_open_test(self, f, compression):
111        self.make_test_archive(f, compression)
112
113        # Read the ZIP archive
114        with zipfile.ZipFile(f, "r", compression) as zipfp:
115            zipdata1 = []
116            zipopen1 = zipfp.open(TESTFN)
117            while True:
118                read_data = zipopen1.read(256)
119                if not read_data:
120                    break
121                zipdata1.append(read_data)
122
123            zipdata2 = []
124            zipopen2 = zipfp.open("another"+os.extsep+"name")
125            while True:
126                read_data = zipopen2.read(256)
127                if not read_data:
128                    break
129                zipdata2.append(read_data)
130
131            self.assertEqual(''.join(zipdata1), self.data)
132            self.assertEqual(''.join(zipdata2), self.data)
133
134    def test_open_stored(self):
135        for f in (TESTFN2, TemporaryFile(), StringIO()):
136            self.zip_open_test(f, zipfile.ZIP_STORED)
137
138    def test_open_via_zip_info(self):
139        # Create the ZIP archive
140        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
141            zipfp.writestr("name", "foo")
142            zipfp.writestr("name", "bar")
143
144        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
145            infos = zipfp.infolist()
146            data = ""
147            for info in infos:
148                data += zipfp.open(info).read()
149            self.assertTrue(data == "foobar" or data == "barfoo")
150            data = ""
151            for info in infos:
152                data += zipfp.read(info)
153            self.assertTrue(data == "foobar" or data == "barfoo")
154
155    def zip_random_open_test(self, f, compression):
156        self.make_test_archive(f, compression)
157
158        # Read the ZIP archive
159        with zipfile.ZipFile(f, "r", compression) as zipfp:
160            zipdata1 = []
161            zipopen1 = zipfp.open(TESTFN)
162            while True:
163                read_data = zipopen1.read(randint(1, 1024))
164                if not read_data:
165                    break
166                zipdata1.append(read_data)
167
168            self.assertEqual(''.join(zipdata1), self.data)
169
170    def test_random_open_stored(self):
171        for f in (TESTFN2, TemporaryFile(), StringIO()):
172            self.zip_random_open_test(f, zipfile.ZIP_STORED)
173
174    def zip_readline_test(self, f, compression):
175        self.make_test_archive(f, compression)
176
177        # Read the ZIP archive
178        with zipfile.ZipFile(f, "r") as zipfp:
179            zipopen = zipfp.open(TESTFN)
180            for line in self.line_gen:
181                linedata = zipopen.readline()
182                self.assertEqual(linedata, line + '\n')
183
184    def zip_readlines_test(self, f, compression):
185        self.make_test_archive(f, compression)
186
187        # Read the ZIP archive
188        with zipfile.ZipFile(f, "r") as zipfp:
189            ziplines = zipfp.open(TESTFN).readlines()
190            for line, zipline in zip(self.line_gen, ziplines):
191                self.assertEqual(zipline, line + '\n')
192
193    def zip_iterlines_test(self, f, compression):
194        self.make_test_archive(f, compression)
195
196        # Read the ZIP archive
197        with zipfile.ZipFile(f, "r") as zipfp:
198            for line, zipline in zip(self.line_gen, zipfp.open(TESTFN)):
199                self.assertEqual(zipline, line + '\n')
200
201    def test_readline_stored(self):
202        for f in (TESTFN2, TemporaryFile(), StringIO()):
203            self.zip_readline_test(f, zipfile.ZIP_STORED)
204
205    def test_readlines_stored(self):
206        for f in (TESTFN2, TemporaryFile(), StringIO()):
207            self.zip_readlines_test(f, zipfile.ZIP_STORED)
208
209    def test_iterlines_stored(self):
210        for f in (TESTFN2, TemporaryFile(), StringIO()):
211            self.zip_iterlines_test(f, zipfile.ZIP_STORED)
212
213    @skipUnless(zlib, "requires zlib")
214    def test_deflated(self):
215        for f in (TESTFN2, TemporaryFile(), StringIO()):
216            self.zip_test(f, zipfile.ZIP_DEFLATED)
217
218    @skipUnless(zlib, "requires zlib")
219    def test_open_deflated(self):
220        for f in (TESTFN2, TemporaryFile(), StringIO()):
221            self.zip_open_test(f, zipfile.ZIP_DEFLATED)
222
223    @skipUnless(zlib, "requires zlib")
224    def test_random_open_deflated(self):
225        for f in (TESTFN2, TemporaryFile(), StringIO()):
226            self.zip_random_open_test(f, zipfile.ZIP_DEFLATED)
227
228    @skipUnless(zlib, "requires zlib")
229    def test_readline_deflated(self):
230        for f in (TESTFN2, TemporaryFile(), StringIO()):
231            self.zip_readline_test(f, zipfile.ZIP_DEFLATED)
232
233    @skipUnless(zlib, "requires zlib")
234    def test_readlines_deflated(self):
235        for f in (TESTFN2, TemporaryFile(), StringIO()):
236            self.zip_readlines_test(f, zipfile.ZIP_DEFLATED)
237
238    @skipUnless(zlib, "requires zlib")
239    def test_iterlines_deflated(self):
240        for f in (TESTFN2, TemporaryFile(), StringIO()):
241            self.zip_iterlines_test(f, zipfile.ZIP_DEFLATED)
242
243    @skipUnless(zlib, "requires zlib")
244    def test_low_compression(self):
245        # Checks for cases where compressed data is larger than original
246        # Create the ZIP archive
247        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
248            zipfp.writestr("strfile", '12')
249
250        # Get an open object for strfile
251        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp:
252            openobj = zipfp.open("strfile")
253            self.assertEqual(openobj.read(1), '1')
254            self.assertEqual(openobj.read(1), '2')
255
256    def test_absolute_arcnames(self):
257        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
258            zipfp.write(TESTFN, "/absolute")
259
260        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
261            self.assertEqual(zipfp.namelist(), ["absolute"])
262
263    def test_append_to_zip_file(self):
264        # Test appending to an existing zipfile
265        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
266            zipfp.write(TESTFN, TESTFN)
267
268        with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
269            zipfp.writestr("strfile", self.data)
270            self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
271
272    def test_append_to_non_zip_file(self):
273        # Test appending to an existing file that is not a zipfile
274        # NOTE: this test fails if len(d) < 22 because of the first
275        # line "fpin.seek(-22, 2)" in _EndRecData
276        d = 'I am not a ZipFile!'*10
277        f = file(TESTFN2, 'wb')
278        f.write(d)
279        f.close()
280        with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
281            zipfp.write(TESTFN, TESTFN)
282
283        f = file(TESTFN2, 'rb')
284        f.seek(len(d))
285        with zipfile.ZipFile(f, "r") as zipfp:
286            self.assertEqual(zipfp.namelist(), [TESTFN])
287        f.close()
288
289    def test_write_default_name(self):
290        # Check that calling ZipFile.write without arcname specified produces the expected result
291        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
292            zipfp.write(TESTFN)
293            self.assertEqual(zipfp.read(TESTFN), file(TESTFN).read())
294
295    @skipUnless(zlib, "requires zlib")
296    def test_per_file_compression(self):
297        # Check that files within a Zip archive can have different compression options
298        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
299            zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
300            zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
301            sinfo = zipfp.getinfo('storeme')
302            dinfo = zipfp.getinfo('deflateme')
303            self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
304            self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
305
306    def test_write_to_readonly(self):
307        # Check that trying to call write() on a readonly ZipFile object
308        # raises a RuntimeError
309        with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
310            zipfp.writestr("somefile.txt", "bogus")
311
312        with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
313            self.assertRaises(RuntimeError, zipfp.write, TESTFN)
314
315    def test_extract(self):
316        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
317            for fpath, fdata in SMALL_TEST_DATA:
318                zipfp.writestr(fpath, fdata)
319
320        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
321            for fpath, fdata in SMALL_TEST_DATA:
322                writtenfile = zipfp.extract(fpath)
323
324                # make sure it was written to the right place
325                if os.path.isabs(fpath):
326                    correctfile = os.path.join(os.getcwd(), fpath[1:])
327                else:
328                    correctfile = os.path.join(os.getcwd(), fpath)
329                correctfile = os.path.normpath(correctfile)
330
331                self.assertEqual(writtenfile, correctfile)
332
333                # make sure correct data is in correct file
334                self.assertEqual(fdata, file(writtenfile, "rb").read())
335
336                os.remove(writtenfile)
337
338        # remove the test file subdirectories
339        shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
340
341    def test_extract_all(self):
342        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
343            for fpath, fdata in SMALL_TEST_DATA:
344                zipfp.writestr(fpath, fdata)
345
346        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
347            zipfp.extractall()
348            for fpath, fdata in SMALL_TEST_DATA:
349                if os.path.isabs(fpath):
350                    outfile = os.path.join(os.getcwd(), fpath[1:])
351                else:
352                    outfile = os.path.join(os.getcwd(), fpath)
353
354                self.assertEqual(fdata, file(outfile, "rb").read())
355
356                os.remove(outfile)
357
358        # remove the test file subdirectories
359        shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
360
361    def zip_test_writestr_permissions(self, f, compression):
362        # Make sure that writestr creates files with mode 0600,
363        # when it is passed a name rather than a ZipInfo instance.
364
365        self.make_test_archive(f, compression)
366        with zipfile.ZipFile(f, "r") as zipfp:
367            zinfo = zipfp.getinfo('strfile')
368            self.assertEqual(zinfo.external_attr, 0600 << 16)
369
370    def test_writestr_permissions(self):
371        for f in (TESTFN2, TemporaryFile(), StringIO()):
372            self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
373
374    def test_close(self):
375        """Check that the zipfile is closed after the 'with' block."""
376        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
377            for fpath, fdata in SMALL_TEST_DATA:
378                zipfp.writestr(fpath, fdata)
379                self.assertTrue(zipfp.fp is not None, 'zipfp is not open')
380        self.assertTrue(zipfp.fp is None, 'zipfp is not closed')
381
382        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
383            self.assertTrue(zipfp.fp is not None, 'zipfp is not open')
384        self.assertTrue(zipfp.fp is None, 'zipfp is not closed')
385
386    def test_close_on_exception(self):
387        """Check that the zipfile is closed if an exception is raised in the
388        'with' block."""
389        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
390            for fpath, fdata in SMALL_TEST_DATA:
391                zipfp.writestr(fpath, fdata)
392
393        try:
394            with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
395                raise zipfile.BadZipfile()
396        except zipfile.BadZipfile:
397            self.assertTrue(zipfp2.fp is None, 'zipfp is not closed')
398
399    def tearDown(self):
400        unlink(TESTFN)
401        unlink(TESTFN2)
402
403
404class TestZip64InSmallFiles(unittest.TestCase):
405    # These tests test the ZIP64 functionality without using large files,
406    # see test_zipfile64 for proper tests.
407
408    def setUp(self):
409        self._limit = zipfile.ZIP64_LIMIT
410        zipfile.ZIP64_LIMIT = 5
411
412        line_gen = ("Test of zipfile line %d." % i for i in range(0, FIXEDTEST_SIZE))
413        self.data = '\n'.join(line_gen)
414
415        # Make a source file with some lines
416        fp = open(TESTFN, "wb")
417        fp.write(self.data)
418        fp.close()
419
420    def large_file_exception_test(self, f, compression):
421        with zipfile.ZipFile(f, "w", compression) as zipfp:
422            self.assertRaises(zipfile.LargeZipFile,
423                    zipfp.write, TESTFN, "another"+os.extsep+"name")
424
425    def large_file_exception_test2(self, f, compression):
426        with zipfile.ZipFile(f, "w", compression) as zipfp:
427            self.assertRaises(zipfile.LargeZipFile,
428                    zipfp.writestr, "another"+os.extsep+"name", self.data)
429
430    def test_large_file_exception(self):
431        for f in (TESTFN2, TemporaryFile(), StringIO()):
432            self.large_file_exception_test(f, zipfile.ZIP_STORED)
433            self.large_file_exception_test2(f, zipfile.ZIP_STORED)
434
435    def zip_test(self, f, compression):
436        # Create the ZIP archive
437        with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
438            zipfp.write(TESTFN, "another"+os.extsep+"name")
439            zipfp.write(TESTFN, TESTFN)
440            zipfp.writestr("strfile", self.data)
441
442        # Read the ZIP archive
443        with zipfile.ZipFile(f, "r", compression) as zipfp:
444            self.assertEqual(zipfp.read(TESTFN), self.data)
445            self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
446            self.assertEqual(zipfp.read("strfile"), self.data)
447
448            # Print the ZIP directory
449            fp = StringIO()
450            stdout = sys.stdout
451            try:
452                sys.stdout = fp
453                zipfp.printdir()
454            finally:
455                sys.stdout = stdout
456
457            directory = fp.getvalue()
458            lines = directory.splitlines()
459            self.assertEquals(len(lines), 4) # Number of files + header
460
461            self.assertTrue('File Name' in lines[0])
462            self.assertTrue('Modified' in lines[0])
463            self.assertTrue('Size' in lines[0])
464
465            fn, date, time, size = lines[1].split()
466            self.assertEquals(fn, 'another.name')
467            # XXX: timestamp is not tested
468            self.assertEquals(size, str(len(self.data)))
469
470            # Check the namelist
471            names = zipfp.namelist()
472            self.assertEquals(len(names), 3)
473            self.assertTrue(TESTFN in names)
474            self.assertTrue("another"+os.extsep+"name" in names)
475            self.assertTrue("strfile" in names)
476
477            # Check infolist
478            infos = zipfp.infolist()
479            names = [ i.filename for i in infos ]
480            self.assertEquals(len(names), 3)
481            self.assertTrue(TESTFN in names)
482            self.assertTrue("another"+os.extsep+"name" in names)
483            self.assertTrue("strfile" in names)
484            for i in infos:
485                self.assertEquals(i.file_size, len(self.data))
486
487            # check getinfo
488            for nm in (TESTFN, "another"+os.extsep+"name", "strfile"):
489                info = zipfp.getinfo(nm)
490                self.assertEquals(info.filename, nm)
491                self.assertEquals(info.file_size, len(self.data))
492
493            # Check that testzip doesn't raise an exception
494            zipfp.testzip()
495
496    def test_stored(self):
497        for f in (TESTFN2, TemporaryFile(), StringIO()):
498            self.zip_test(f, zipfile.ZIP_STORED)
499
500    @skipUnless(zlib, "requires zlib")
501    def test_deflated(self):
502        for f in (TESTFN2, TemporaryFile(), StringIO()):
503            self.zip_test(f, zipfile.ZIP_DEFLATED)
504
505    def test_absolute_arcnames(self):
506        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
507                             allowZip64=True) as zipfp:
508            zipfp.write(TESTFN, "/absolute")
509
510        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
511            self.assertEqual(zipfp.namelist(), ["absolute"])
512
513    def tearDown(self):
514        zipfile.ZIP64_LIMIT = self._limit
515        unlink(TESTFN)
516        unlink(TESTFN2)
517
518
519class PyZipFileTests(unittest.TestCase):
520    def test_write_pyfile(self):
521        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
522            fn = __file__
523            if fn.endswith('.pyc') or fn.endswith('.pyo'):
524                fn = fn[:-1]
525
526            zipfp.writepy(fn)
527
528            bn = os.path.basename(fn)
529            self.assertTrue(bn not in zipfp.namelist())
530            self.assertTrue(bn + 'o' in zipfp.namelist() or
531                            bn + 'c' in zipfp.namelist())
532
533        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
534            fn = __file__
535            if fn.endswith('.pyc') or fn.endswith('.pyo'):
536                fn = fn[:-1]
537
538            zipfp.writepy(fn, "testpackage")
539
540            bn = "%s/%s"%("testpackage", os.path.basename(fn))
541            self.assertTrue(bn not in zipfp.namelist())
542            self.assertTrue(bn + 'o' in zipfp.namelist() or
543                            bn + 'c' in zipfp.namelist())
544
545    def test_write_python_package(self):
546        import email
547        packagedir = os.path.dirname(email.__file__)
548
549        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
550            zipfp.writepy(packagedir)
551
552            # Check for a couple of modules at different levels of the hieararchy
553            names = zipfp.namelist()
554            self.assertTrue('email/__init__.pyo' in names or
555                            'email/__init__.pyc' in names)
556            self.assertTrue('email/mime/text.pyo' in names or
557                            'email/mime/text.pyc' in names)
558
559    def test_write_python_directory(self):
560        os.mkdir(TESTFN2)
561        try:
562            fp = open(os.path.join(TESTFN2, "mod1.py"), "w")
563            fp.write("print 42\n")
564            fp.close()
565
566            fp = open(os.path.join(TESTFN2, "mod2.py"), "w")
567            fp.write("print 42 * 42\n")
568            fp.close()
569
570            fp = open(os.path.join(TESTFN2, "mod2.txt"), "w")
571            fp.write("bla bla bla\n")
572            fp.close()
573
574            zipfp  = zipfile.PyZipFile(TemporaryFile(), "w")
575            zipfp.writepy(TESTFN2)
576
577            names = zipfp.namelist()
578            self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names)
579            self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names)
580            self.assertTrue('mod2.txt' not in names)
581
582        finally:
583            shutil.rmtree(TESTFN2)
584
585    def test_write_non_pyfile(self):
586        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
587            file(TESTFN, 'w').write('most definitely not a python file')
588            self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
589            os.remove(TESTFN)
590
591
592class OtherTests(unittest.TestCase):
593    def test_unicode_filenames(self):
594        with zipfile.ZipFile(TESTFN, "w") as zf:
595            zf.writestr(u"foo.txt", "Test for unicode filename")
596            zf.writestr(u"\xf6.txt", "Test for unicode filename")
597            self.assertTrue(isinstance(zf.infolist()[0].filename, unicode))
598
599        with zipfile.ZipFile(TESTFN, "r") as zf:
600            self.assertEqual(zf.filelist[0].filename, "foo.txt")
601            self.assertEqual(zf.filelist[1].filename, u"\xf6.txt")
602
603    def test_create_non_existent_file_for_append(self):
604        if os.path.exists(TESTFN):
605            os.unlink(TESTFN)
606
607        filename = 'testfile.txt'
608        content = 'hello, world. this is some content.'
609
610        try:
611            with zipfile.ZipFile(TESTFN, 'a') as zf:
612                zf.writestr(filename, content)
613        except IOError:
614            self.fail('Could not append data to a non-existent zip file.')
615
616        self.assertTrue(os.path.exists(TESTFN))
617
618        with zipfile.ZipFile(TESTFN, 'r') as zf:
619            self.assertEqual(zf.read(filename), content)
620
621    def test_close_erroneous_file(self):
622        # This test checks that the ZipFile constructor closes the file object
623        # it opens if there's an error in the file.  If it doesn't, the traceback
624        # holds a reference to the ZipFile object and, indirectly, the file object.
625        # On Windows, this causes the os.unlink() call to fail because the
626        # underlying file is still open.  This is SF bug #412214.
627        #
628        fp = open(TESTFN, "w")
629        fp.write("this is not a legal zip file\n")
630        fp.close()
631        try:
632            zf = zipfile.ZipFile(TESTFN)
633        except zipfile.BadZipfile:
634            pass
635
636    def test_is_zip_erroneous_file(self):
637        # This test checks that the is_zipfile function correctly identifies
638        # a file that is not a zip file
639
640        # - passing a filename
641        with open(TESTFN, "w") as fp:
642            fp.write("this is not a legal zip file\n")
643        chk = zipfile.is_zipfile(TESTFN)
644        self.assertTrue(not chk)
645        # - passing a file object
646        with open(TESTFN, "rb") as fp:
647            chk = zipfile.is_zipfile(fp)
648            self.assertTrue(not chk)
649        # - passing a file-like object
650        fp = StringIO()
651        fp.write("this is not a legal zip file\n")
652        chk = zipfile.is_zipfile(fp)
653        self.assertTrue(not chk)
654        fp.seek(0,0)
655        chk = zipfile.is_zipfile(fp)
656        self.assertTrue(not chk)
657
658    def test_is_zip_valid_file(self):
659        # This test checks that the is_zipfile function correctly identifies
660        # a file that is a zip file
661
662        # - passing a filename
663        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
664            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
665        chk = zipfile.is_zipfile(TESTFN)
666        self.assertTrue(chk)
667        # - passing a file object
668        with open(TESTFN, "rb") as fp:
669            chk = zipfile.is_zipfile(fp)
670            self.assertTrue(chk)
671            fp.seek(0,0)
672            zip_contents = fp.read()
673        # - passing a file-like object
674        fp = StringIO()
675        fp.write(zip_contents)
676        chk = zipfile.is_zipfile(fp)
677        self.assertTrue(chk)
678        fp.seek(0,0)
679        chk = zipfile.is_zipfile(fp)
680        self.assertTrue(chk)
681
682    def test_non_existent_file_raises_IOError(self):
683        # make sure we don't raise an AttributeError when a partially-constructed
684        # ZipFile instance is finalized; this tests for regression on SF tracker
685        # bug #403871.
686
687        # The bug we're testing for caused an AttributeError to be raised
688        # when a ZipFile instance was created for a file that did not
689        # exist; the .fp member was not initialized but was needed by the
690        # __del__() method.  Since the AttributeError is in the __del__(),
691        # it is ignored, but the user should be sufficiently annoyed by
692        # the message on the output that regression will be noticed
693        # quickly.
694        self.assertRaises(IOError, zipfile.ZipFile, TESTFN)
695
696    def test_empty_file_raises_BadZipFile(self):
697        f = open(TESTFN, 'w')
698        f.close()
699        self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN)
700
701        f = open(TESTFN, 'w')
702        f.write("short file")
703        f.close()
704        self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN)
705
706    def test_closed_zip_raises_RuntimeError(self):
707        # Verify that testzip() doesn't swallow inappropriate exceptions.
708        data = StringIO()
709        with zipfile.ZipFile(data, mode="w") as zipf:
710            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
711
712        # This is correct; calling .read on a closed ZipFile should throw
713        # a RuntimeError, and so should calling .testzip.  An earlier
714        # version of .testzip would swallow this exception (and any other)
715        # and report that the first file in the archive was corrupt.
716        self.assertRaises(RuntimeError, zipf.read, "foo.txt")
717        self.assertRaises(RuntimeError, zipf.open, "foo.txt")
718        self.assertRaises(RuntimeError, zipf.testzip)
719        self.assertRaises(RuntimeError, zipf.writestr, "bogus.txt", "bogus")
720        file(TESTFN, 'w').write('zipfile test data')
721        self.assertRaises(RuntimeError, zipf.write, TESTFN)
722
723    def test_bad_constructor_mode(self):
724        # Check that bad modes passed to ZipFile constructor are caught
725        self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "q")
726
727    def test_bad_open_mode(self):
728        # Check that bad modes passed to ZipFile.open are caught
729        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
730            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
731
732        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
733        # read the data to make sure the file is there
734            zipf.read("foo.txt")
735            self.assertRaises(RuntimeError, zipf.open, "foo.txt", "q")
736
737    def test_read0(self):
738        # Check that calling read(0) on a ZipExtFile object returns an empty
739        # string and doesn't advance file pointer
740        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
741            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
742            # read the data to make sure the file is there
743            f = zipf.open("foo.txt")
744            for i in xrange(FIXEDTEST_SIZE):
745                self.assertEqual(f.read(0), '')
746
747            self.assertEqual(f.read(), "O, for a Muse of Fire!")
748
749    def test_open_non_existent_item(self):
750        # Check that attempting to call open() for an item that doesn't
751        # exist in the archive raises a RuntimeError
752        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
753            self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
754
755    def test_bad_compression_mode(self):
756        # Check that bad compression methods passed to ZipFile.open are caught
757        self.assertRaises(RuntimeError, zipfile.ZipFile, TESTFN, "w", -1)
758
759    def test_null_byte_in_filename(self):
760        # Check that a filename containing a null byte is properly terminated
761        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
762            zipf.writestr("foo.txt\x00qqq", "O, for a Muse of Fire!")
763            self.assertEqual(zipf.namelist(), ['foo.txt'])
764
765    def test_struct_sizes(self):
766        # check that ZIP internal structure sizes are calculated correctly
767        self.assertEqual(zipfile.sizeEndCentDir, 22)
768        self.assertEqual(zipfile.sizeCentralDir, 46)
769        self.assertEqual(zipfile.sizeEndCentDir64, 56)
770        self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
771
772    def test_comments(self):
773        # This test checks that comments on the archive are handled properly
774
775        # check default comment is empty
776        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
777            self.assertEqual(zipf.comment, '')
778            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
779
780        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
781            self.assertEqual(zipf.comment, '')
782
783        # check a simple short comment
784        comment = 'Bravely taking to his feet, he beat a very brave retreat.'
785        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
786            zipf.comment = comment
787            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
788        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
789            self.assertEqual(zipf.comment, comment)
790
791        # check a comment of max length
792        comment2 = ''.join(['%d' % (i**3 % 10) for i in xrange((1 << 16)-1)])
793        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
794            zipf.comment = comment2
795            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
796
797        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
798            self.assertEqual(zipf.comment, comment2)
799
800        # check a comment that is too long is truncated
801        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
802            zipf.comment = comment2 + 'oops'
803            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
804        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
805            self.assertEqual(zipf.comment, comment2)
806
807    def tearDown(self):
808        unlink(TESTFN)
809        unlink(TESTFN2)
810
811
812class DecryptionTests(unittest.TestCase):
813    # This test checks that ZIP decryption works. Since the library does not
814    # support encryption at the moment, we use a pre-generated encrypted
815    # ZIP file
816
817    data = (
818    'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
819    '\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
820    '\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
821    'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
822    '\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
823    '\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
824    '\x00\x00L\x00\x00\x00\x00\x00' )
825    data2 = (
826    'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
827    '\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
828    '\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
829    'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
830    '\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
831    '\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
832    'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
833    '\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
834
835    plain = 'zipfile.py encryption test'
836    plain2 = '\x00'*512
837
838    def setUp(self):
839        fp = open(TESTFN, "wb")
840        fp.write(self.data)
841        fp.close()
842        self.zip = zipfile.ZipFile(TESTFN, "r")
843        fp = open(TESTFN2, "wb")
844        fp.write(self.data2)
845        fp.close()
846        self.zip2 = zipfile.ZipFile(TESTFN2, "r")
847
848    def tearDown(self):
849        self.zip.close()
850        os.unlink(TESTFN)
851        self.zip2.close()
852        os.unlink(TESTFN2)
853
854    def test_no_password(self):
855        # Reading the encrypted file without password
856        # must generate a RunTime exception
857        self.assertRaises(RuntimeError, self.zip.read, "test.txt")
858        self.assertRaises(RuntimeError, self.zip2.read, "zero")
859
860    def test_bad_password(self):
861        self.zip.setpassword("perl")
862        self.assertRaises(RuntimeError, self.zip.read, "test.txt")
863        self.zip2.setpassword("perl")
864        self.assertRaises(RuntimeError, self.zip2.read, "zero")
865
866    @skipUnless(zlib, "requires zlib")
867    def test_good_password(self):
868        self.zip.setpassword("python")
869        self.assertEquals(self.zip.read("test.txt"), self.plain)
870        self.zip2.setpassword("12345")
871        self.assertEquals(self.zip2.read("zero"), self.plain2)
872
873
874class TestsWithRandomBinaryFiles(unittest.TestCase):
875    def setUp(self):
876        datacount = randint(16, 64)*1024 + randint(1, 1024)
877        self.data = ''.join((struct.pack('<f', random()*randint(-1000, 1000)) for i in xrange(datacount)))
878
879        # Make a source file with some lines
880        fp = open(TESTFN, "wb")
881        fp.write(self.data)
882        fp.close()
883
884    def tearDown(self):
885        unlink(TESTFN)
886        unlink(TESTFN2)
887
888    def make_test_archive(self, f, compression):
889        # Create the ZIP archive
890        with zipfile.ZipFile(f, "w", compression) as zipfp:
891            zipfp.write(TESTFN, "another"+os.extsep+"name")
892            zipfp.write(TESTFN, TESTFN)
893
894    def zip_test(self, f, compression):
895        self.make_test_archive(f, compression)
896
897        # Read the ZIP archive
898        with zipfile.ZipFile(f, "r", compression) as zipfp:
899            testdata = zipfp.read(TESTFN)
900            self.assertEqual(len(testdata), len(self.data))
901            self.assertEqual(testdata, self.data)
902            self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
903
904    def test_stored(self):
905        for f in (TESTFN2, TemporaryFile(), StringIO()):
906            self.zip_test(f, zipfile.ZIP_STORED)
907
908    def zip_open_test(self, f, compression):
909        self.make_test_archive(f, compression)
910
911        # Read the ZIP archive
912        with zipfile.ZipFile(f, "r", compression) as zipfp:
913            zipdata1 = []
914            zipopen1 = zipfp.open(TESTFN)
915            while True:
916                read_data = zipopen1.read(256)
917                if not read_data:
918                    break
919                zipdata1.append(read_data)
920
921            zipdata2 = []
922            zipopen2 = zipfp.open("another"+os.extsep+"name")
923            while True:
924                read_data = zipopen2.read(256)
925                if not read_data:
926                    break
927                zipdata2.append(read_data)
928
929            testdata1 = ''.join(zipdata1)
930            self.assertEqual(len(testdata1), len(self.data))
931            self.assertEqual(testdata1, self.data)
932
933            testdata2 = ''.join(zipdata2)
934            self.assertEqual(len(testdata1), len(self.data))
935            self.assertEqual(testdata1, self.data)
936
937    def test_open_stored(self):
938        for f in (TESTFN2, TemporaryFile(), StringIO()):
939            self.zip_open_test(f, zipfile.ZIP_STORED)
940
941    def zip_random_open_test(self, f, compression):
942        self.make_test_archive(f, compression)
943
944        # Read the ZIP archive
945        with zipfile.ZipFile(f, "r", compression) as zipfp:
946            zipdata1 = []
947            zipopen1 = zipfp.open(TESTFN)
948            while True:
949                read_data = zipopen1.read(randint(1, 1024))
950                if not read_data:
951                    break
952                zipdata1.append(read_data)
953
954            testdata = ''.join(zipdata1)
955            self.assertEqual(len(testdata), len(self.data))
956            self.assertEqual(testdata, self.data)
957
958    def test_random_open_stored(self):
959        for f in (TESTFN2, TemporaryFile(), StringIO()):
960            self.zip_random_open_test(f, zipfile.ZIP_STORED)
961
962
963@skipUnless(zlib, "requires zlib")
964class TestsWithMultipleOpens(unittest.TestCase):
965    def setUp(self):
966        # Create the ZIP archive
967        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
968            zipfp.writestr('ones', '1'*FIXEDTEST_SIZE)
969            zipfp.writestr('twos', '2'*FIXEDTEST_SIZE)
970
971    def test_same_file(self):
972        # Verify that (when the ZipFile is in control of creating file objects)
973        # multiple open() calls can be made without interfering with each other.
974        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
975            zopen1 = zipf.open('ones')
976            zopen2 = zipf.open('ones')
977            data1 = zopen1.read(500)
978            data2 = zopen2.read(500)
979            data1 += zopen1.read(500)
980            data2 += zopen2.read(500)
981            self.assertEqual(data1, data2)
982
983    def test_different_file(self):
984        # Verify that (when the ZipFile is in control of creating file objects)
985        # multiple open() calls can be made without interfering with each other.
986        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
987            zopen1 = zipf.open('ones')
988            zopen2 = zipf.open('twos')
989            data1 = zopen1.read(500)
990            data2 = zopen2.read(500)
991            data1 += zopen1.read(500)
992            data2 += zopen2.read(500)
993            self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
994            self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
995
996    def test_interleaved(self):
997        # Verify that (when the ZipFile is in control of creating file objects)
998        # multiple open() calls can be made without interfering with each other.
999        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
1000            zopen1 = zipf.open('ones')
1001            data1 = zopen1.read(500)
1002            zopen2 = zipf.open('twos')
1003            data2 = zopen2.read(500)
1004            data1 += zopen1.read(500)
1005            data2 += zopen2.read(500)
1006            self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
1007            self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
1008
1009    def tearDown(self):
1010        unlink(TESTFN2)
1011
1012
1013class TestWithDirectory(unittest.TestCase):
1014    def setUp(self):
1015        os.mkdir(TESTFN2)
1016
1017    def test_extract_dir(self):
1018        with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
1019            zipf.extractall(TESTFN2)
1020        self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
1021        self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
1022        self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
1023
1024    def test_bug_6050(self):
1025        # Extraction should succeed if directories already exist
1026        os.mkdir(os.path.join(TESTFN2, "a"))
1027        self.test_extract_dir()
1028
1029    def test_store_dir(self):
1030        os.mkdir(os.path.join(TESTFN2, "x"))
1031        zipf = zipfile.ZipFile(TESTFN, "w")
1032        zipf.write(os.path.join(TESTFN2, "x"), "x")
1033        self.assertTrue(zipf.filelist[0].filename.endswith("x/"))
1034
1035    def tearDown(self):
1036        shutil.rmtree(TESTFN2)
1037        if os.path.exists(TESTFN):
1038            unlink(TESTFN)
1039
1040
1041class UniversalNewlineTests(unittest.TestCase):
1042    def setUp(self):
1043        self.line_gen = ["Test of zipfile line %d." % i for i in xrange(FIXEDTEST_SIZE)]
1044        self.seps = ('\r', '\r\n', '\n')
1045        self.arcdata, self.arcfiles = {}, {}
1046        for n, s in enumerate(self.seps):
1047            self.arcdata[s] = s.join(self.line_gen) + s
1048            self.arcfiles[s] = '%s-%d' % (TESTFN, n)
1049            open(self.arcfiles[s], "wb").write(self.arcdata[s])
1050
1051    def make_test_archive(self, f, compression):
1052        # Create the ZIP archive
1053        with zipfile.ZipFile(f, "w", compression) as zipfp:
1054            for fn in self.arcfiles.values():
1055                zipfp.write(fn, fn)
1056
1057    def read_test(self, f, compression):
1058        self.make_test_archive(f, compression)
1059
1060        # Read the ZIP archive
1061        with zipfile.ZipFile(f, "r") as zipfp:
1062            for sep, fn in self.arcfiles.items():
1063                zipdata = zipfp.open(fn, "rU").read()
1064                self.assertEqual(self.arcdata[sep], zipdata)
1065
1066    def readline_test(self, f, compression):
1067        self.make_test_archive(f, compression)
1068
1069        # Read the ZIP archive
1070        with zipfile.ZipFile(f, "r") as zipfp:
1071            for sep, fn in self.arcfiles.items():
1072                zipopen = zipfp.open(fn, "rU")
1073                for line in self.line_gen:
1074                    linedata = zipopen.readline()
1075                    self.assertEqual(linedata, line + '\n')
1076
1077    def readlines_test(self, f, compression):
1078        self.make_test_archive(f, compression)
1079
1080        # Read the ZIP archive
1081        with zipfile.ZipFile(f, "r") as zipfp:
1082            for sep, fn in self.arcfiles.items():
1083                ziplines = zipfp.open(fn, "rU").readlines()
1084                for line, zipline in zip(self.line_gen, ziplines):
1085                    self.assertEqual(zipline, line + '\n')
1086
1087    def iterlines_test(self, f, compression):
1088        self.make_test_archive(f, compression)
1089
1090        # Read the ZIP archive
1091        with zipfile.ZipFile(f, "r") as zipfp:
1092            for sep, fn in self.arcfiles.items():
1093                for line, zipline in zip(self.line_gen, zipfp.open(fn, "rU")):
1094                    self.assertEqual(zipline, line + '\n')
1095
1096    def test_read_stored(self):
1097        for f in (TESTFN2, TemporaryFile(), StringIO()):
1098            self.read_test(f, zipfile.ZIP_STORED)
1099
1100    def test_readline_stored(self):
1101        for f in (TESTFN2, TemporaryFile(), StringIO()):
1102            self.readline_test(f, zipfile.ZIP_STORED)
1103
1104    def test_readlines_stored(self):
1105        for f in (TESTFN2, TemporaryFile(), StringIO()):
1106            self.readlines_test(f, zipfile.ZIP_STORED)
1107
1108    def test_iterlines_stored(self):
1109        for f in (TESTFN2, TemporaryFile(), StringIO()):
1110            self.iterlines_test(f, zipfile.ZIP_STORED)
1111
1112    @skipUnless(zlib, "requires zlib")
1113    def test_read_deflated(self):
1114        for f in (TESTFN2, TemporaryFile(), StringIO()):
1115            self.read_test(f, zipfile.ZIP_DEFLATED)
1116
1117    @skipUnless(zlib, "requires zlib")
1118    def test_readline_deflated(self):
1119        for f in (TESTFN2, TemporaryFile(), StringIO()):
1120            self.readline_test(f, zipfile.ZIP_DEFLATED)
1121
1122    @skipUnless(zlib, "requires zlib")
1123    def test_readlines_deflated(self):
1124        for f in (TESTFN2, TemporaryFile(), StringIO()):
1125            self.readlines_test(f, zipfile.ZIP_DEFLATED)
1126
1127    @skipUnless(zlib, "requires zlib")
1128    def test_iterlines_deflated(self):
1129        for f in (TESTFN2, TemporaryFile(), StringIO()):
1130            self.iterlines_test(f, zipfile.ZIP_DEFLATED)
1131
1132    def tearDown(self):
1133        for sep, fn in self.arcfiles.items():
1134            os.remove(fn)
1135        unlink(TESTFN)
1136        unlink(TESTFN2)
1137
1138
1139def test_main():
1140    run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests,
1141                 PyZipFileTests, DecryptionTests, TestsWithMultipleOpens,
1142                 TestWithDirectory, UniversalNewlineTests,
1143                 TestsWithRandomBinaryFiles)
1144
1145if __name__ == "__main__":
1146    test_main()
1147