@@ -676,12 +676,12 @@ def test_add_file_after_2107(self):
676676 self .skipTest (f"Linux VFS/XFS kernel bug detected: { mtime_ns = } " )
677677
678678 with zipfile .ZipFile (TESTFN2 , "w" ) as zipfp :
679- self .assertRaises (struct . error , zipfp .write , TESTFN )
679+ self .assertRaises (ValueError , zipfp .write , TESTFN )
680680
681681 with zipfile .ZipFile (TESTFN2 , "w" , strict_timestamps = False ) as zipfp :
682682 zipfp .write (TESTFN )
683683 zinfo = zipfp .getinfo (TESTFN )
684- self .assertEqual (zinfo .date_time , (2107 , 12 , 31 , 23 , 59 , 59 ))
684+ self .assertEqual (zinfo .date_time , (2107 , 12 , 31 , 23 , 59 , 58 ))
685685
686686
687687@requires_zlib ()
@@ -4476,6 +4476,10 @@ def test_create_zipinfo_before_1980(self):
44764476 self .assertRaises (ValueError ,
44774477 zipfile .ZipInfo , 'seventies' , (1979 , 1 , 1 , 0 , 0 , 0 ))
44784478
4479+ def test_create_zipinfo_after_2107 (self ):
4480+ self .assertRaises (ValueError ,
4481+ zipfile .ZipInfo , 'future' , (2108 , 1 , 1 , 0 , 0 , 0 ))
4482+
44794483 def test_create_empty_zipinfo_repr (self ):
44804484 """Before bpo-26185, repr() on empty ZipInfo object was failing."""
44814485 zi = zipfile .ZipInfo (filename = "empty" )
@@ -5528,6 +5532,50 @@ def test_from_file(self):
55285532 self .assertFalse (zi .is_dir ())
55295533 self .assertEqual (zi .file_size , os .path .getsize (__file__ ))
55305534
5535+ def test_from_file_rejects_timestamp_after_2107 (self ):
5536+ st = mock .Mock (st_mode = stat .S_IFREG | 0o644 ,
5537+ st_mtime = 2 ** 63 , st_size = 5 )
5538+ mtime = (2108 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , - 1 )
5539+ with mock .patch .object (zipfile .os , 'stat' , return_value = st ), \
5540+ mock .patch .object (zipfile .time , 'localtime' , return_value = mtime ):
5541+ with self .assertRaises (ValueError ):
5542+ zipfile .ZipInfo .from_file ('future' )
5543+
5544+ def test_from_file_clamps_timestamp_after_2107_round_trip (self ):
5545+ st = mock .Mock (st_mode = stat .S_IFREG | 0o644 ,
5546+ st_mtime = 2 ** 63 , st_size = 5 )
5547+ mtime = (2108 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , - 1 )
5548+ with mock .patch .object (zipfile .os , 'stat' , return_value = st ), \
5549+ mock .patch .object (zipfile .time , 'localtime' , return_value = mtime ):
5550+ zinfo = zipfile .ZipInfo .from_file (
5551+ 'future' , strict_timestamps = False )
5552+
5553+ expected = (2107 , 12 , 31 , 23 , 59 , 58 )
5554+ self .assertEqual (zinfo .date_time , expected )
5555+ archive = io .BytesIO ()
5556+ with zipfile .ZipFile (archive , 'w' ) as zf :
5557+ zf .writestr (zinfo , b'future' )
5558+ with zipfile .ZipFile (archive ) as zf :
5559+ self .assertEqual (zf .getinfo ('future' ).date_time , expected )
5560+
5561+ def test_from_file_clamps_localtime_overflow (self ):
5562+ cases = (
5563+ (2 ** 63 , (2107 , 12 , 31 , 23 , 59 , 58 )),
5564+ (- 2 ** 63 , (1980 , 1 , 1 , 0 , 0 , 0 )),
5565+ )
5566+ for exception in (OverflowError , OSError ):
5567+ for timestamp , expected in cases :
5568+ with self .subTest (exception = exception , timestamp = timestamp ):
5569+ st = mock .Mock (st_mode = stat .S_IFREG | 0o644 ,
5570+ st_mtime = timestamp , st_size = 5 )
5571+ with mock .patch .object (
5572+ zipfile .os , 'stat' , return_value = st ), \
5573+ mock .patch .object (zipfile .time , 'localtime' ,
5574+ side_effect = exception ):
5575+ zinfo = zipfile .ZipInfo .from_file (
5576+ 'future' , strict_timestamps = False )
5577+ self .assertEqual (zinfo .date_time , expected )
5578+
55315579 def test_from_file_pathlike (self ):
55325580 zi = zipfile .ZipInfo .from_file (FakePath (__file__ ))
55335581 self .assertEqual (posixpath .basename (zi .filename ), 'test_core.py' )
0 commit comments