@@ -1482,6 +1482,289 @@ def _prepare_zip_from_test_files(cls, zfname, test_files, force_zip64=False):
14821482 fh .write (data )
14831483 return list (zh .infolist ())
14841484
1485+ class AbstractCopyTests (RepackHelperMixin ):
1486+ @classmethod
1487+ def setUpClass (cls ):
1488+ cls .test_files = cls ._prepare_test_files ()
1489+
1490+ def tearDown (self ):
1491+ unlink (TESTFN )
1492+
1493+ def test_copy_by_name (self ):
1494+ for i in range (3 ):
1495+ with self .subTest (i = i , filename = self .test_files [i ][0 ]):
1496+ zinfos = self ._prepare_zip_from_test_files (TESTFN , self .test_files )
1497+ with zipfile .ZipFile (TESTFN , 'a' , self .compression ) as zh :
1498+ zi_new = {
1499+ ** ComparableZipInfo (zinfos [i ]),
1500+ 'filename' : 'file.txt' ,
1501+ 'orig_filename' : 'file.txt' ,
1502+ 'header_offset' : zh .start_dir ,
1503+ }
1504+ zh .copy (self .test_files [i ][0 ], 'file.txt' )
1505+
1506+ # check infolist
1507+ self .assertEqual (
1508+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1509+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1510+ )
1511+
1512+ # check NameToInfo cache
1513+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file.txt' )), zi_new )
1514+
1515+ # check content
1516+ self .assertEqual (
1517+ zh .read (zi_new ['filename' ]),
1518+ zh .read (zinfos [i ].filename ),
1519+ )
1520+
1521+ # make sure the zip file is still valid
1522+ with zipfile .ZipFile (TESTFN ) as zh :
1523+ self .assertIsNone (zh .testzip ())
1524+
1525+ def test_copy_by_zinfo (self ):
1526+ for i in range (3 ):
1527+ with self .subTest (i = i , filename = self .test_files [i ][0 ]):
1528+ zinfos = self ._prepare_zip_from_test_files (TESTFN , self .test_files )
1529+ with zipfile .ZipFile (TESTFN , 'a' , self .compression ) as zh :
1530+ zi_new = {
1531+ ** ComparableZipInfo (zinfos [i ]),
1532+ 'filename' : 'file.txt' ,
1533+ 'orig_filename' : 'file.txt' ,
1534+ 'header_offset' : zh .start_dir ,
1535+ }
1536+ zh .copy (zh .infolist ()[i ], 'file.txt' )
1537+
1538+ # check infolist
1539+ self .assertEqual (
1540+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1541+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1542+ )
1543+
1544+ # check NameToInfo cache
1545+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file.txt' )), zi_new )
1546+
1547+ # check content
1548+ self .assertEqual (
1549+ zh .read (zi_new ['filename' ]),
1550+ zh .read (zinfos [i ].filename ),
1551+ )
1552+
1553+ # make sure the zip file is still valid
1554+ with zipfile .ZipFile (TESTFN ) as zh :
1555+ self .assertIsNone (zh .testzip ())
1556+
1557+ def test_copy_zip64 (self ):
1558+ for i in range (3 ):
1559+ with self .subTest (i = i , filename = self .test_files [i ][0 ]):
1560+ zinfos = self ._prepare_zip_from_test_files (TESTFN , self .test_files , force_zip64 = True )
1561+ with zipfile .ZipFile (TESTFN , 'a' , self .compression ) as zh :
1562+ zi_new = {
1563+ ** ComparableZipInfo (zinfos [i ]),
1564+ 'filename' : 'file.txt' ,
1565+ 'orig_filename' : 'file.txt' ,
1566+ 'header_offset' : zh .start_dir ,
1567+ }
1568+ zh .copy (self .test_files [i ][0 ], 'file.txt' )
1569+
1570+ # check infolist
1571+ self .assertEqual (
1572+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1573+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1574+ )
1575+
1576+ # check NameToInfo cache
1577+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file.txt' )), zi_new )
1578+
1579+ # check content
1580+ self .assertEqual (
1581+ zh .read (zi_new ['filename' ]),
1582+ zh .read (zinfos [i ].filename ),
1583+ )
1584+
1585+ # make sure the zip file is still valid
1586+ with zipfile .ZipFile (TESTFN ) as zh :
1587+ self .assertIsNone (zh .testzip ())
1588+
1589+ def test_copy_data_descriptor (self ):
1590+ for i in range (3 ):
1591+ with self .subTest (i = i , filename = self .test_files [i ][0 ]):
1592+ with open (TESTFN , 'wb' ) as fh :
1593+ zinfos = self ._prepare_zip_from_test_files (Unseekable (fh ), self .test_files )
1594+ with zipfile .ZipFile (TESTFN , 'a' , self .compression ) as zh :
1595+ zi_new = {
1596+ ** ComparableZipInfo (zinfos [i ]),
1597+ 'filename' : 'file.txt' ,
1598+ 'orig_filename' : 'file.txt' ,
1599+ 'header_offset' : zh .start_dir ,
1600+ }
1601+ zh .copy (self .test_files [i ][0 ], 'file.txt' )
1602+
1603+ # check infolist
1604+ self .assertEqual (
1605+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1606+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1607+ )
1608+
1609+ # check NameToInfo cache
1610+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file.txt' )), zi_new )
1611+
1612+ # check content
1613+ self .assertEqual (
1614+ zh .read (zi_new ['filename' ]),
1615+ zh .read (zinfos [i ].filename ),
1616+ )
1617+
1618+ # make sure the zip file is still valid
1619+ with zipfile .ZipFile (TESTFN ) as zh :
1620+ self .assertIsNone (zh .testzip ())
1621+
1622+ def test_copy_target_exist (self ):
1623+ for i in (1 ,):
1624+ with self .subTest (i = i , filename = self .test_files [i ][0 ]):
1625+ zinfos = self ._prepare_zip_from_test_files (TESTFN , self .test_files )
1626+ with zipfile .ZipFile (TESTFN , 'a' , self .compression ) as zh :
1627+ zi_new = {
1628+ ** ComparableZipInfo (zinfos [i ]),
1629+ 'filename' : 'file2.txt' ,
1630+ 'orig_filename' : 'file2.txt' ,
1631+ 'header_offset' : zh .start_dir ,
1632+ }
1633+ zh .copy (self .test_files [i ][0 ], 'file2.txt' )
1634+
1635+ # check infolist
1636+ self .assertEqual (
1637+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1638+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1639+ )
1640+
1641+ # check NameToInfo cache
1642+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file2.txt' )), zi_new )
1643+
1644+ # check content
1645+ self .assertEqual (
1646+ zh .read (zi_new ['filename' ]),
1647+ zh .read (zinfos [i ].filename ),
1648+ )
1649+
1650+ # make sure the zip file is still valid
1651+ with zipfile .ZipFile (TESTFN ) as zh :
1652+ self .assertIsNone (zh .testzip ())
1653+
1654+ @mock .patch .object (zipfile , '_ZipRepacker' )
1655+ def test_copy_closed (self , m_repack ):
1656+ self ._prepare_zip_from_test_files (TESTFN , self .test_files )
1657+ with zipfile .ZipFile (TESTFN , 'a' ) as zh :
1658+ zh .close ()
1659+ with self .assertRaises (ValueError ):
1660+ zh .copy (self .test_files [0 ][0 ], 'file.txt' )
1661+ m_repack .assert_not_called ()
1662+
1663+ @mock .patch .object (zipfile , '_ZipRepacker' )
1664+ def test_copy_writing (self , m_repack ):
1665+ self ._prepare_zip_from_test_files (TESTFN , self .test_files )
1666+ with zipfile .ZipFile (TESTFN , 'a' ) as zh :
1667+ with zh .open ('newfile.txt' , 'w' ):
1668+ with self .assertRaises (ValueError ):
1669+ zh .copy (self .test_files [0 ][0 ], 'file.txt' )
1670+ m_repack .assert_not_called ()
1671+
1672+ @mock .patch .object (zipfile , '_ZipRepacker' )
1673+ def test_copy_unseekble (self , m_repack ):
1674+ with open (TESTFN , 'wb' ) as fh :
1675+ with zipfile .ZipFile (Unseekable (fh ), 'w' ) as zh :
1676+ for file , data in self .test_files :
1677+ zh .writestr (file , data )
1678+
1679+ with self .assertRaises (io .UnsupportedOperation ):
1680+ zh .copy (zh .infolist ()[0 ], 'file.txt' )
1681+ m_repack .assert_not_called ()
1682+
1683+ def test_copy_mode_w (self ):
1684+ with zipfile .ZipFile (TESTFN , 'w' ) as zh :
1685+ for file , data in self .test_files :
1686+ zh .writestr (file , data )
1687+ zinfos = list (zh .infolist ())
1688+
1689+ zi_new = {
1690+ ** ComparableZipInfo (zinfos [0 ]),
1691+ 'filename' : 'file.txt' ,
1692+ 'orig_filename' : 'file.txt' ,
1693+ 'header_offset' : zh .start_dir ,
1694+ }
1695+ zh .copy (zh .infolist ()[0 ], 'file.txt' )
1696+
1697+ # check infolist
1698+ self .assertEqual (
1699+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1700+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1701+ )
1702+
1703+ # check NameToInfo cache
1704+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file.txt' )), zi_new )
1705+
1706+ # check content
1707+ self .assertEqual (
1708+ zh .read (zi_new ['filename' ]),
1709+ zh .read (zinfos [0 ].filename ),
1710+ )
1711+
1712+ # make sure the zip file is still valid
1713+ with zipfile .ZipFile (TESTFN ) as zh :
1714+ self .assertIsNone (zh .testzip ())
1715+
1716+ def test_copy_mode_x (self ):
1717+ with zipfile .ZipFile (TESTFN , 'x' ) as zh :
1718+ for file , data in self .test_files :
1719+ zh .writestr (file , data )
1720+ zinfos = list (zh .infolist ())
1721+
1722+ zi_new = {
1723+ ** ComparableZipInfo (zinfos [0 ]),
1724+ 'filename' : 'file.txt' ,
1725+ 'orig_filename' : 'file.txt' ,
1726+ 'header_offset' : zh .start_dir ,
1727+ }
1728+ zh .copy (zh .infolist ()[0 ], 'file.txt' )
1729+
1730+ # check infolist
1731+ self .assertEqual (
1732+ [ComparableZipInfo (zi ) for zi in zh .infolist ()],
1733+ [* (ComparableZipInfo (zi ) for zi in zinfos ), zi_new ],
1734+ )
1735+
1736+ # check NameToInfo cache
1737+ self .assertEqual (ComparableZipInfo (zh .getinfo ('file.txt' )), zi_new )
1738+
1739+ # check content
1740+ self .assertEqual (
1741+ zh .read (zi_new ['filename' ]),
1742+ zh .read (zinfos [0 ].filename ),
1743+ )
1744+
1745+ # make sure the zip file is still valid
1746+ with zipfile .ZipFile (TESTFN ) as zh :
1747+ self .assertIsNone (zh .testzip ())
1748+
1749+ class StoredCopyTests (AbstractCopyTests , unittest .TestCase ):
1750+ compression = zipfile .ZIP_STORED
1751+
1752+ @requires_zlib ()
1753+ class DeflateCopyTests (AbstractCopyTests , unittest .TestCase ):
1754+ compression = zipfile .ZIP_DEFLATED
1755+
1756+ @requires_bz2 ()
1757+ class Bzip2CopyTests (AbstractCopyTests , unittest .TestCase ):
1758+ compression = zipfile .ZIP_BZIP2
1759+
1760+ @requires_lzma ()
1761+ class LzmaCopyTests (AbstractCopyTests , unittest .TestCase ):
1762+ compression = zipfile .ZIP_LZMA
1763+
1764+ @requires_zstd ()
1765+ class ZstdCopyTests (AbstractCopyTests , unittest .TestCase ):
1766+ compression = zipfile .ZIP_ZSTANDARD
1767+
14851768class AbstractRemoveTests (RepackHelperMixin ):
14861769 @classmethod
14871770 def setUpClass (cls ):
@@ -3432,7 +3715,7 @@ def test_calc_local_file_entry_size(self):
34323715
34333716 self .assertEqual (
34343717 repacker ._calc_local_file_entry_size (fz , zi ),
3435- 43 ,
3718+ ( 30 , 8 , 0 , 5 , 0 ) ,
34363719 )
34373720
34383721 # data descriptor
@@ -3444,7 +3727,7 @@ def test_calc_local_file_entry_size(self):
34443727
34453728 self .assertEqual (
34463729 repacker ._calc_local_file_entry_size (fz , zi ),
3447- 59 ,
3730+ ( 30 , 8 , 0 , 5 , 16 ) ,
34483731 )
34493732
34503733 # data descriptor (unsigned)
@@ -3457,7 +3740,7 @@ def test_calc_local_file_entry_size(self):
34573740
34583741 self .assertEqual (
34593742 repacker ._calc_local_file_entry_size (fz , zi ),
3460- 55 ,
3743+ ( 30 , 8 , 0 , 5 , 12 ) ,
34613744 )
34623745
34633746 def test_calc_local_file_entry_size_zip64 (self ):
@@ -3472,7 +3755,7 @@ def test_calc_local_file_entry_size_zip64(self):
34723755
34733756 self .assertEqual (
34743757 repacker ._calc_local_file_entry_size (fz , zi ),
3475- 63 ,
3758+ ( 30 , 8 , 20 , 5 , 0 ) ,
34763759 )
34773760
34783761 # data descriptor + zip64
@@ -3484,7 +3767,7 @@ def test_calc_local_file_entry_size_zip64(self):
34843767
34853768 self .assertEqual (
34863769 repacker ._calc_local_file_entry_size (fz , zi ),
3487- 87 ,
3770+ ( 30 , 8 , 20 , 5 , 24 ) ,
34883771 )
34893772
34903773 # data descriptor (unsigned) + zip64
@@ -3497,7 +3780,7 @@ def test_calc_local_file_entry_size_zip64(self):
34973780
34983781 self .assertEqual (
34993782 repacker ._calc_local_file_entry_size (fz , zi ),
3500- 83 ,
3783+ ( 30 , 8 , 20 , 5 , 20 ) ,
35013784 )
35023785
35033786 def test_copy_bytes (self ):
0 commit comments