| 1 | # We can test part of the module without zlib.
|
|---|
| 2 | try:
|
|---|
| 3 | import zlib
|
|---|
| 4 | except ImportError:
|
|---|
| 5 | zlib = None
|
|---|
| 6 |
|
|---|
| 7 | import zipfile, os, unittest, sys, shutil
|
|---|
| 8 |
|
|---|
| 9 | from StringIO import StringIO
|
|---|
| 10 | from tempfile import TemporaryFile
|
|---|
| 11 |
|
|---|
| 12 | from test.test_support import TESTFN, run_unittest
|
|---|
| 13 |
|
|---|
| 14 | TESTFN2 = TESTFN + "2"
|
|---|
| 15 |
|
|---|
| 16 | class TestsWithSourceFile(unittest.TestCase):
|
|---|
| 17 | def setUp(self):
|
|---|
| 18 | line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000))
|
|---|
| 19 | self.data = '\n'.join(line_gen)
|
|---|
| 20 |
|
|---|
| 21 | # Make a source file with some lines
|
|---|
| 22 | fp = open(TESTFN, "wb")
|
|---|
| 23 | fp.write(self.data)
|
|---|
| 24 | fp.close()
|
|---|
| 25 |
|
|---|
| 26 | def zipTest(self, f, compression):
|
|---|
| 27 | # Create the ZIP archive
|
|---|
| 28 | zipfp = zipfile.ZipFile(f, "w", compression)
|
|---|
| 29 | zipfp.write(TESTFN, "another"+os.extsep+"name")
|
|---|
| 30 | zipfp.write(TESTFN, TESTFN)
|
|---|
| 31 | zipfp.writestr("strfile", self.data)
|
|---|
| 32 | zipfp.close()
|
|---|
| 33 |
|
|---|
| 34 | # Read the ZIP archive
|
|---|
| 35 | zipfp = zipfile.ZipFile(f, "r", compression)
|
|---|
| 36 | self.assertEqual(zipfp.read(TESTFN), self.data)
|
|---|
| 37 | self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
|
|---|
| 38 | self.assertEqual(zipfp.read("strfile"), self.data)
|
|---|
| 39 |
|
|---|
| 40 | # Print the ZIP directory
|
|---|
| 41 | fp = StringIO()
|
|---|
| 42 | stdout = sys.stdout
|
|---|
| 43 | try:
|
|---|
| 44 | sys.stdout = fp
|
|---|
| 45 |
|
|---|
| 46 | zipfp.printdir()
|
|---|
| 47 | finally:
|
|---|
| 48 | sys.stdout = stdout
|
|---|
| 49 |
|
|---|
| 50 | directory = fp.getvalue()
|
|---|
| 51 | lines = directory.splitlines()
|
|---|
| 52 | self.assertEquals(len(lines), 4) # Number of files + header
|
|---|
| 53 |
|
|---|
| 54 | self.assert_('File Name' in lines[0])
|
|---|
| 55 | self.assert_('Modified' in lines[0])
|
|---|
| 56 | self.assert_('Size' in lines[0])
|
|---|
| 57 |
|
|---|
| 58 | fn, date, time, size = lines[1].split()
|
|---|
| 59 | self.assertEquals(fn, 'another.name')
|
|---|
| 60 | # XXX: timestamp is not tested
|
|---|
| 61 | self.assertEquals(size, str(len(self.data)))
|
|---|
| 62 |
|
|---|
| 63 | # Check the namelist
|
|---|
| 64 | names = zipfp.namelist()
|
|---|
| 65 | self.assertEquals(len(names), 3)
|
|---|
| 66 | self.assert_(TESTFN in names)
|
|---|
| 67 | self.assert_("another"+os.extsep+"name" in names)
|
|---|
| 68 | self.assert_("strfile" in names)
|
|---|
| 69 |
|
|---|
| 70 | # Check infolist
|
|---|
| 71 | infos = zipfp.infolist()
|
|---|
| 72 | names = [ i.filename for i in infos ]
|
|---|
| 73 | self.assertEquals(len(names), 3)
|
|---|
| 74 | self.assert_(TESTFN in names)
|
|---|
| 75 | self.assert_("another"+os.extsep+"name" in names)
|
|---|
| 76 | self.assert_("strfile" in names)
|
|---|
| 77 | for i in infos:
|
|---|
| 78 | self.assertEquals(i.file_size, len(self.data))
|
|---|
| 79 |
|
|---|
| 80 | # check getinfo
|
|---|
| 81 | for nm in (TESTFN, "another"+os.extsep+"name", "strfile"):
|
|---|
| 82 | info = zipfp.getinfo(nm)
|
|---|
| 83 | self.assertEquals(info.filename, nm)
|
|---|
| 84 | self.assertEquals(info.file_size, len(self.data))
|
|---|
| 85 |
|
|---|
| 86 | # Check that testzip doesn't raise an exception
|
|---|
| 87 | zipfp.testzip()
|
|---|
| 88 |
|
|---|
| 89 |
|
|---|
| 90 | zipfp.close()
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 | def testStored(self):
|
|---|
| 96 | for f in (TESTFN2, TemporaryFile(), StringIO()):
|
|---|
| 97 | self.zipTest(f, zipfile.ZIP_STORED)
|
|---|
| 98 |
|
|---|
| 99 | if zlib:
|
|---|
| 100 | def testDeflated(self):
|
|---|
| 101 | for f in (TESTFN2, TemporaryFile(), StringIO()):
|
|---|
| 102 | self.zipTest(f, zipfile.ZIP_DEFLATED)
|
|---|
| 103 |
|
|---|
| 104 | def testAbsoluteArcnames(self):
|
|---|
| 105 | zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
|
|---|
| 106 | zipfp.write(TESTFN, "/absolute")
|
|---|
| 107 | zipfp.close()
|
|---|
| 108 |
|
|---|
| 109 | zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
|
|---|
| 110 | self.assertEqual(zipfp.namelist(), ["absolute"])
|
|---|
| 111 | zipfp.close()
|
|---|
| 112 |
|
|---|
| 113 |
|
|---|
| 114 | def tearDown(self):
|
|---|
| 115 | os.remove(TESTFN)
|
|---|
| 116 | os.remove(TESTFN2)
|
|---|
| 117 |
|
|---|
| 118 | class TestZip64InSmallFiles(unittest.TestCase):
|
|---|
| 119 | # These tests test the ZIP64 functionality without using large files,
|
|---|
| 120 | # see test_zipfile64 for proper tests.
|
|---|
| 121 |
|
|---|
| 122 | def setUp(self):
|
|---|
| 123 | self._limit = zipfile.ZIP64_LIMIT
|
|---|
| 124 | zipfile.ZIP64_LIMIT = 5
|
|---|
| 125 |
|
|---|
| 126 | line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000))
|
|---|
| 127 | self.data = '\n'.join(line_gen)
|
|---|
| 128 |
|
|---|
| 129 | # Make a source file with some lines
|
|---|
| 130 | fp = open(TESTFN, "wb")
|
|---|
| 131 | fp.write(self.data)
|
|---|
| 132 | fp.close()
|
|---|
| 133 |
|
|---|
| 134 | def largeFileExceptionTest(self, f, compression):
|
|---|
| 135 | zipfp = zipfile.ZipFile(f, "w", compression)
|
|---|
| 136 | self.assertRaises(zipfile.LargeZipFile,
|
|---|
| 137 | zipfp.write, TESTFN, "another"+os.extsep+"name")
|
|---|
| 138 | zipfp.close()
|
|---|
| 139 |
|
|---|
| 140 | def largeFileExceptionTest2(self, f, compression):
|
|---|
| 141 | zipfp = zipfile.ZipFile(f, "w", compression)
|
|---|
| 142 | self.assertRaises(zipfile.LargeZipFile,
|
|---|
| 143 | zipfp.writestr, "another"+os.extsep+"name", self.data)
|
|---|
| 144 | zipfp.close()
|
|---|
| 145 |
|
|---|
| 146 | def testLargeFileException(self):
|
|---|
| 147 | for f in (TESTFN2, TemporaryFile(), StringIO()):
|
|---|
| 148 | self.largeFileExceptionTest(f, zipfile.ZIP_STORED)
|
|---|
| 149 | self.largeFileExceptionTest2(f, zipfile.ZIP_STORED)
|
|---|
| 150 |
|
|---|
| 151 | def zipTest(self, f, compression):
|
|---|
| 152 | # Create the ZIP archive
|
|---|
| 153 | zipfp = zipfile.ZipFile(f, "w", compression, allowZip64=True)
|
|---|
| 154 | zipfp.write(TESTFN, "another"+os.extsep+"name")
|
|---|
| 155 | zipfp.write(TESTFN, TESTFN)
|
|---|
| 156 | zipfp.writestr("strfile", self.data)
|
|---|
| 157 | zipfp.close()
|
|---|
| 158 |
|
|---|
| 159 | # Read the ZIP archive
|
|---|
| 160 | zipfp = zipfile.ZipFile(f, "r", compression)
|
|---|
| 161 | self.assertEqual(zipfp.read(TESTFN), self.data)
|
|---|
| 162 | self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
|
|---|
| 163 | self.assertEqual(zipfp.read("strfile"), self.data)
|
|---|
| 164 |
|
|---|
| 165 | # Print the ZIP directory
|
|---|
| 166 | fp = StringIO()
|
|---|
| 167 | stdout = sys.stdout
|
|---|
| 168 | try:
|
|---|
| 169 | sys.stdout = fp
|
|---|
| 170 |
|
|---|
| 171 | zipfp.printdir()
|
|---|
| 172 | finally:
|
|---|
| 173 | sys.stdout = stdout
|
|---|
| 174 |
|
|---|
| 175 | directory = fp.getvalue()
|
|---|
| 176 | lines = directory.splitlines()
|
|---|
| 177 | self.assertEquals(len(lines), 4) # Number of files + header
|
|---|
| 178 |
|
|---|
| 179 | self.assert_('File Name' in lines[0])
|
|---|
| 180 | self.assert_('Modified' in lines[0])
|
|---|
| 181 | self.assert_('Size' in lines[0])
|
|---|
| 182 |
|
|---|
| 183 | fn, date, time, size = lines[1].split()
|
|---|
| 184 | self.assertEquals(fn, 'another.name')
|
|---|
| 185 | # XXX: timestamp is not tested
|
|---|
| 186 | self.assertEquals(size, str(len(self.data)))
|
|---|
| 187 |
|
|---|
| 188 | # Check the namelist
|
|---|
| 189 | names = zipfp.namelist()
|
|---|
| 190 | self.assertEquals(len(names), 3)
|
|---|
| 191 | self.assert_(TESTFN in names)
|
|---|
| 192 | self.assert_("another"+os.extsep+"name" in names)
|
|---|
| 193 | self.assert_("strfile" in names)
|
|---|
| 194 |
|
|---|
| 195 | # Check infolist
|
|---|
| 196 | infos = zipfp.infolist()
|
|---|
| 197 | names = [ i.filename for i in infos ]
|
|---|
| 198 | self.assertEquals(len(names), 3)
|
|---|
| 199 | self.assert_(TESTFN in names)
|
|---|
| 200 | self.assert_("another"+os.extsep+"name" in names)
|
|---|
| 201 | self.assert_("strfile" in names)
|
|---|
| 202 | for i in infos:
|
|---|
| 203 | self.assertEquals(i.file_size, len(self.data))
|
|---|
| 204 |
|
|---|
| 205 | # check getinfo
|
|---|
| 206 | for nm in (TESTFN, "another"+os.extsep+"name", "strfile"):
|
|---|
| 207 | info = zipfp.getinfo(nm)
|
|---|
| 208 | self.assertEquals(info.filename, nm)
|
|---|
| 209 | self.assertEquals(info.file_size, len(self.data))
|
|---|
| 210 |
|
|---|
| 211 | # Check that testzip doesn't raise an exception
|
|---|
| 212 | zipfp.testzip()
|
|---|
| 213 |
|
|---|
| 214 |
|
|---|
| 215 | zipfp.close()
|
|---|
| 216 |
|
|---|
| 217 | def testStored(self):
|
|---|
| 218 | for f in (TESTFN2, TemporaryFile(), StringIO()):
|
|---|
| 219 | self.zipTest(f, zipfile.ZIP_STORED)
|
|---|
| 220 |
|
|---|
| 221 |
|
|---|
| 222 | if zlib:
|
|---|
| 223 | def testDeflated(self):
|
|---|
| 224 | for f in (TESTFN2, TemporaryFile(), StringIO()):
|
|---|
| 225 | self.zipTest(f, zipfile.ZIP_DEFLATED)
|
|---|
| 226 |
|
|---|
| 227 | def testAbsoluteArcnames(self):
|
|---|
| 228 | zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, allowZip64=True)
|
|---|
| 229 | zipfp.write(TESTFN, "/absolute")
|
|---|
| 230 | zipfp.close()
|
|---|
| 231 |
|
|---|
| 232 | zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
|
|---|
| 233 | self.assertEqual(zipfp.namelist(), ["absolute"])
|
|---|
| 234 | zipfp.close()
|
|---|
| 235 |
|
|---|
| 236 |
|
|---|
| 237 | def tearDown(self):
|
|---|
| 238 | zipfile.ZIP64_LIMIT = self._limit
|
|---|
| 239 | os.remove(TESTFN)
|
|---|
| 240 | os.remove(TESTFN2)
|
|---|
| 241 |
|
|---|
| 242 | class PyZipFileTests(unittest.TestCase):
|
|---|
| 243 | def testWritePyfile(self):
|
|---|
| 244 | zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
|---|
| 245 | fn = __file__
|
|---|
| 246 | if fn.endswith('.pyc') or fn.endswith('.pyo'):
|
|---|
| 247 | fn = fn[:-1]
|
|---|
| 248 |
|
|---|
| 249 | zipfp.writepy(fn)
|
|---|
| 250 |
|
|---|
| 251 | bn = os.path.basename(fn)
|
|---|
| 252 | self.assert_(bn not in zipfp.namelist())
|
|---|
| 253 | self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist())
|
|---|
| 254 | zipfp.close()
|
|---|
| 255 |
|
|---|
| 256 |
|
|---|
| 257 | zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
|---|
| 258 | fn = __file__
|
|---|
| 259 | if fn.endswith('.pyc') or fn.endswith('.pyo'):
|
|---|
| 260 | fn = fn[:-1]
|
|---|
| 261 |
|
|---|
| 262 | zipfp.writepy(fn, "testpackage")
|
|---|
| 263 |
|
|---|
| 264 | bn = "%s/%s"%("testpackage", os.path.basename(fn))
|
|---|
| 265 | self.assert_(bn not in zipfp.namelist())
|
|---|
| 266 | self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist())
|
|---|
| 267 | zipfp.close()
|
|---|
| 268 |
|
|---|
| 269 | def testWritePythonPackage(self):
|
|---|
| 270 | import email
|
|---|
| 271 | packagedir = os.path.dirname(email.__file__)
|
|---|
| 272 |
|
|---|
| 273 | zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
|---|
| 274 | zipfp.writepy(packagedir)
|
|---|
| 275 |
|
|---|
| 276 | # Check for a couple of modules at different levels of the hieararchy
|
|---|
| 277 | names = zipfp.namelist()
|
|---|
| 278 | self.assert_('email/__init__.pyo' in names or 'email/__init__.pyc' in names)
|
|---|
| 279 | self.assert_('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names)
|
|---|
| 280 |
|
|---|
| 281 | def testWritePythonDirectory(self):
|
|---|
| 282 | os.mkdir(TESTFN2)
|
|---|
| 283 | try:
|
|---|
| 284 | fp = open(os.path.join(TESTFN2, "mod1.py"), "w")
|
|---|
| 285 | fp.write("print 42\n")
|
|---|
| 286 | fp.close()
|
|---|
| 287 |
|
|---|
| 288 | fp = open(os.path.join(TESTFN2, "mod2.py"), "w")
|
|---|
| 289 | fp.write("print 42 * 42\n")
|
|---|
| 290 | fp.close()
|
|---|
| 291 |
|
|---|
| 292 | fp = open(os.path.join(TESTFN2, "mod2.txt"), "w")
|
|---|
| 293 | fp.write("bla bla bla\n")
|
|---|
| 294 | fp.close()
|
|---|
| 295 |
|
|---|
| 296 | zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
|---|
| 297 | zipfp.writepy(TESTFN2)
|
|---|
| 298 |
|
|---|
| 299 | names = zipfp.namelist()
|
|---|
| 300 | self.assert_('mod1.pyc' in names or 'mod1.pyo' in names)
|
|---|
| 301 | self.assert_('mod2.pyc' in names or 'mod2.pyo' in names)
|
|---|
| 302 | self.assert_('mod2.txt' not in names)
|
|---|
| 303 |
|
|---|
| 304 | finally:
|
|---|
| 305 | shutil.rmtree(TESTFN2)
|
|---|
| 306 |
|
|---|
| 307 |
|
|---|
| 308 |
|
|---|
| 309 | class OtherTests(unittest.TestCase):
|
|---|
| 310 | def testCloseErroneousFile(self):
|
|---|
| 311 | # This test checks that the ZipFile constructor closes the file object
|
|---|
| 312 | # it opens if there's an error in the file. If it doesn't, the traceback
|
|---|
| 313 | # holds a reference to the ZipFile object and, indirectly, the file object.
|
|---|
| 314 | # On Windows, this causes the os.unlink() call to fail because the
|
|---|
| 315 | # underlying file is still open. This is SF bug #412214.
|
|---|
| 316 | #
|
|---|
| 317 | fp = open(TESTFN, "w")
|
|---|
| 318 | fp.write("this is not a legal zip file\n")
|
|---|
| 319 | fp.close()
|
|---|
| 320 | try:
|
|---|
| 321 | zf = zipfile.ZipFile(TESTFN)
|
|---|
| 322 | except zipfile.BadZipfile:
|
|---|
| 323 | os.unlink(TESTFN)
|
|---|
| 324 |
|
|---|
| 325 | def testNonExistentFileRaisesIOError(self):
|
|---|
| 326 | # make sure we don't raise an AttributeError when a partially-constructed
|
|---|
| 327 | # ZipFile instance is finalized; this tests for regression on SF tracker
|
|---|
| 328 | # bug #403871.
|
|---|
| 329 |
|
|---|
| 330 | # The bug we're testing for caused an AttributeError to be raised
|
|---|
| 331 | # when a ZipFile instance was created for a file that did not
|
|---|
| 332 | # exist; the .fp member was not initialized but was needed by the
|
|---|
| 333 | # __del__() method. Since the AttributeError is in the __del__(),
|
|---|
| 334 | # it is ignored, but the user should be sufficiently annoyed by
|
|---|
| 335 | # the message on the output that regression will be noticed
|
|---|
| 336 | # quickly.
|
|---|
| 337 | self.assertRaises(IOError, zipfile.ZipFile, TESTFN)
|
|---|
| 338 |
|
|---|
| 339 | def testClosedZipRaisesRuntimeError(self):
|
|---|
| 340 | # Verify that testzip() doesn't swallow inappropriate exceptions.
|
|---|
| 341 | data = StringIO()
|
|---|
| 342 | zipf = zipfile.ZipFile(data, mode="w")
|
|---|
| 343 | zipf.writestr("foo.txt", "O, for a Muse of Fire!")
|
|---|
| 344 | zipf.close()
|
|---|
| 345 |
|
|---|
| 346 | # This is correct; calling .read on a closed ZipFile should throw
|
|---|
| 347 | # a RuntimeError, and so should calling .testzip. An earlier
|
|---|
| 348 | # version of .testzip would swallow this exception (and any other)
|
|---|
| 349 | # and report that the first file in the archive was corrupt.
|
|---|
| 350 | self.assertRaises(RuntimeError, zipf.testzip)
|
|---|
| 351 |
|
|---|
| 352 | def test_main():
|
|---|
| 353 | run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, PyZipFileTests)
|
|---|
| 354 | #run_unittest(TestZip64InSmallFiles)
|
|---|
| 355 |
|
|---|
| 356 | if __name__ == "__main__":
|
|---|
| 357 | test_main()
|
|---|