@@ -302,26 +302,26 @@ def test_low_compression(self):
302302 self .assertEqual (openobj .read (1 ), b'2' )
303303
304304 def test_writestr_compression (self ):
305- zipfp = zipfile .ZipFile (TESTFN2 , "w" )
306- zipfp .writestr ("b.txt" , "hello world" , compress_type = self .compression )
307- info = zipfp .getinfo ('b.txt' )
308- self .assertEqual (info .compress_type , self .compression )
305+ with zipfile .ZipFile (TESTFN2 , "w" ) as zipfp :
306+ zipfp .writestr ("b.txt" , "hello world" , compress_type = self .compression )
307+ info = zipfp .getinfo ('b.txt' )
308+ self .assertEqual (info .compress_type , self .compression )
309309
310310 def test_writestr_compresslevel (self ):
311- zipfp = zipfile .ZipFile (TESTFN2 , "w" , compresslevel = 1 )
312- zipfp .writestr ("a.txt" , "hello world" , compress_type = self .compression )
313- zipfp .writestr ("b.txt" , "hello world" , compress_type = self .compression ,
314- compresslevel = 2 )
311+ with zipfile .ZipFile (TESTFN2 , "w" , compresslevel = 1 ) as zipfp :
312+ zipfp .writestr ("a.txt" , "hello world" , compress_type = self .compression )
313+ zipfp .writestr ("b.txt" , "hello world" , compress_type = self .compression ,
314+ compresslevel = 2 )
315315
316- # Compression level follows the constructor.
317- a_info = zipfp .getinfo ('a.txt' )
318- self .assertEqual (a_info .compress_type , self .compression )
319- self .assertEqual (a_info .compress_level , 1 )
316+ # Compression level follows the constructor.
317+ a_info = zipfp .getinfo ('a.txt' )
318+ self .assertEqual (a_info .compress_type , self .compression )
319+ self .assertEqual (a_info .compress_level , 1 )
320320
321- # Compression level is overridden.
322- b_info = zipfp .getinfo ('b.txt' )
323- self .assertEqual (b_info .compress_type , self .compression )
324- self .assertEqual (b_info ._compresslevel , 2 )
321+ # Compression level is overridden.
322+ b_info = zipfp .getinfo ('b.txt' )
323+ self .assertEqual (b_info .compress_type , self .compression )
324+ self .assertEqual (b_info ._compresslevel , 2 )
325325
326326 def test_read_return_size (self ):
327327 # Issue #9837: ZipExtFile.read() shouldn't return more bytes
@@ -884,6 +884,8 @@ def make_zip64_file(
884884 self , file_size_64_set = False , file_size_extra = False ,
885885 compress_size_64_set = False , compress_size_extra = False ,
886886 header_offset_64_set = False , header_offset_extra = False ,
887+ extensible_data = b'' ,
888+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
887889 ):
888890 """Generate bytes sequence for a zip with (incomplete) zip64 data.
889891
@@ -937,6 +939,12 @@ def make_zip64_file(
937939
938940 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
939941 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
942+ if end_of_central_dir_size is None :
943+ end_of_central_dir_size = 44 + len (extensible_data )
944+ if offset_to_end_of_central_dir is None :
945+ offset_to_end_of_central_dir = (108
946+ + 8 * len (local_zip64_fields )
947+ + 8 * len (central_zip64_fields ))
940948
941949 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
942950 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -965,14 +973,17 @@ def make_zip64_file(
965973 + filename
966974 + central_extra
967975 # Zip64 end of central directory
968- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
969- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
976+ + b"PK\x06 \x06 "
977+ + struct .pack ('<Q' , end_of_central_dir_size )
978+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
970979 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
971980 + central_dir_size
972981 + offset_to_central_dir
982+ + extensible_data
973983 # Zip64 end of central directory locator
974- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
975- + b"\x00 \x00 \x00 "
984+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
985+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
986+ + b"\x01 \x00 \x00 \x00 "
976987 # end of central directory
977988 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
978989 + b"\x00 \x00 \x00 \x00 "
@@ -1003,6 +1014,7 @@ def test_bad_zip64_extra(self):
10031014 with self .assertRaises (zipfile .BadZipFile ) as e :
10041015 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
10051016 self .assertIn ('file size' , str (e .exception ).lower ())
1017+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
10061018
10071019 # zip64 file size present, zip64 compress size present, one field in
10081020 # extra, expecting two, equals missing compress size.
@@ -1014,6 +1026,7 @@ def test_bad_zip64_extra(self):
10141026 with self .assertRaises (zipfile .BadZipFile ) as e :
10151027 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10161028 self .assertIn ('compress size' , str (e .exception ).lower ())
1029+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10171030
10181031 # zip64 compress size present, no fields in extra, expecting one,
10191032 # equals missing compress size.
@@ -1023,6 +1036,7 @@ def test_bad_zip64_extra(self):
10231036 with self .assertRaises (zipfile .BadZipFile ) as e :
10241037 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10251038 self .assertIn ('compress size' , str (e .exception ).lower ())
1039+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10261040
10271041 # zip64 file size present, zip64 compress size present, zip64 header
10281042 # offset present, two fields in extra, expecting three, equals missing
@@ -1037,6 +1051,7 @@ def test_bad_zip64_extra(self):
10371051 with self .assertRaises (zipfile .BadZipFile ) as e :
10381052 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10391053 self .assertIn ('header offset' , str (e .exception ).lower ())
1054+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10401055
10411056 # zip64 compress size present, zip64 header offset present, one field
10421057 # in extra, expecting two, equals missing header offset
@@ -1049,6 +1064,7 @@ def test_bad_zip64_extra(self):
10491064 with self .assertRaises (zipfile .BadZipFile ) as e :
10501065 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10511066 self .assertIn ('header offset' , str (e .exception ).lower ())
1067+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10521068
10531069 # zip64 file size present, zip64 header offset present, one field in
10541070 # extra, expecting two, equals missing header offset
@@ -1061,6 +1077,7 @@ def test_bad_zip64_extra(self):
10611077 with self .assertRaises (zipfile .BadZipFile ) as e :
10621078 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10631079 self .assertIn ('header offset' , str (e .exception ).lower ())
1080+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10641081
10651082 # zip64 header offset present, no fields in extra, expecting one,
10661083 # equals missing header offset
@@ -1072,6 +1089,63 @@ def test_bad_zip64_extra(self):
10721089 with self .assertRaises (zipfile .BadZipFile ) as e :
10731090 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10741091 self .assertIn ('header offset' , str (e .exception ).lower ())
1092+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1093+
1094+ def test_bad_zip64_end_of_central_dir (self ):
1095+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1096+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1097+ zipfile .ZipFile (io .BytesIO (zipdata ))
1098+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1099+
1100+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1101+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1102+ zipfile .ZipFile (io .BytesIO (zipdata ))
1103+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1104+
1105+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1106+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1107+ zipfile .ZipFile (io .BytesIO (zipdata ))
1108+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1109+
1110+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1111+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1112+ zipfile .ZipFile (io .BytesIO (zipdata ))
1113+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1114+
1115+ def test_zip64_end_of_central_dir_record_not_found (self ):
1116+ zipdata = self .make_zip64_file ()
1117+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1118+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1119+ zipfile .ZipFile (io .BytesIO (zipdata ))
1120+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1121+
1122+ zipdata = self .make_zip64_file (
1123+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1124+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1125+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1126+ zipfile .ZipFile (io .BytesIO (zipdata ))
1127+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1128+
1129+ def test_zip64_extensible_data (self ):
1130+ # These values are what is set in the make_zip64_file method.
1131+ expected_file_size = 8
1132+ expected_compress_size = 8
1133+ expected_header_offset = 0
1134+ expected_content = b"test1234"
1135+
1136+ zipdata = self .make_zip64_file (
1137+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1138+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1139+ zinfo = zf .infolist ()[0 ]
1140+ self .assertEqual (zinfo .file_size , expected_file_size )
1141+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1142+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1143+ self .assertEqual (zf .read (zinfo ), expected_content )
1144+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1145+
1146+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1147+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1148+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10751149
10761150 def test_generated_valid_zip64_extra (self ):
10771151 # These values are what is set in the make_zip64_file method.
@@ -1357,8 +1431,7 @@ def requiresWriteAccess(self, path):
13571431 self .skipTest ('requires write access to the installed location' )
13581432 unlink (filename )
13591433
1360- # TODO: RUSTPYTHON
1361- @unittest .expectedFailure
1434+ @unittest .expectedFailure # TODO: RUSTPYTHON
13621435 def test_write_pyfile (self ):
13631436 self .requiresWriteAccess (os .path .dirname (__file__ ))
13641437 with TemporaryFile () as t , zipfile .PyZipFile (t , "w" ) as zipfp :
@@ -1389,8 +1462,7 @@ def test_write_pyfile(self):
13891462 self .assertNotIn (bn , zipfp .namelist ())
13901463 self .assertCompiledIn (bn , zipfp .namelist ())
13911464
1392- # TODO: RUSTPYTHON
1393- @unittest .expectedFailure
1465+ @unittest .expectedFailure # TODO: RUSTPYTHON
13941466 def test_write_python_package (self ):
13951467 import email
13961468 packagedir = os .path .dirname (email .__file__ )
@@ -1405,8 +1477,7 @@ def test_write_python_package(self):
14051477 self .assertCompiledIn ('email/__init__.py' , names )
14061478 self .assertCompiledIn ('email/mime/text.py' , names )
14071479
1408- # TODO: RUSTPYTHON - AttributeError: module 'os' has no attribute 'supports_effective_ids'
1409- @unittest .expectedFailure
1480+ @unittest .expectedFailure # TODO: RUSTPYTHON; - AttributeError: module 'os' has no attribute 'supports_effective_ids'
14101481 def test_write_filtered_python_package (self ):
14111482 import test
14121483 packagedir = os .path .dirname (test .__file__ )
@@ -1437,8 +1508,7 @@ def filter(path):
14371508 print (reportStr )
14381509 self .assertTrue ('SyntaxError' not in reportStr )
14391510
1440- # TODO: RUSTPYTHON
1441- @unittest .expectedFailure
1511+ @unittest .expectedFailure # TODO: RUSTPYTHON
14421512 def test_write_with_optimization (self ):
14431513 import email
14441514 packagedir = os .path .dirname (email .__file__ )
@@ -2189,13 +2259,15 @@ def test_empty_zipfile(self):
21892259 zipf = zipfile .ZipFile (TESTFN , mode = "r" )
21902260 except zipfile .BadZipFile :
21912261 self .fail ("Unable to create empty ZIP file in 'w' mode" )
2262+ zipf .close ()
21922263
21932264 zipf = zipfile .ZipFile (TESTFN , mode = "a" )
21942265 zipf .close ()
21952266 try :
21962267 zipf = zipfile .ZipFile (TESTFN , mode = "r" )
21972268 except :
21982269 self .fail ("Unable to create empty ZIP file in 'a' mode" )
2270+ zipf .close ()
21992271
22002272 def test_open_empty_file (self ):
22012273 # Issue 1710703: Check that opening a file with less than 22 bytes
@@ -3020,11 +3092,6 @@ def test_write_after_read(self):
30203092 self .assertEqual (data1 , self .data1 )
30213093 self .assertEqual (data2 , self .data2 )
30223094
3023- # TODO: RUSTPYTHON other tests can impact the file descriptor incrementor
3024- # by leaving file handles unclosed. If there are more than 100 files in
3025- # TESTFN and references to them are left unclosed and ungarbage collected
3026- # in another test, then fileno() will always be too high for this test to
3027- # pass. The solution is to increase the number of files from 100 to 200
30283095 def test_many_opens (self ):
30293096 # Verify that read() and open() promptly close the file descriptor,
30303097 # and don't rely on the garbage collector to free resources.
@@ -3348,8 +3415,7 @@ def test_read_zip_with_exe_prepended(self):
33483415 def test_read_zip64_with_exe_prepended (self ):
33493416 self ._test_zip_works (self .exe_zip64 )
33503417
3351- # TODO: RUSTPYTHON
3352- @unittest .expectedFailure
3418+ @unittest .expectedFailure # TODO: RUSTPYTHON
33533419 @unittest .skipUnless (sys .executable , 'sys.executable required.' )
33543420 @unittest .skipUnless (os .access ('/bin/bash' , os .X_OK ),
33553421 'Test relies on #!/bin/bash working.' )
@@ -3358,8 +3424,7 @@ def test_execute_zip2(self):
33583424 output = subprocess .check_output ([self .exe_zip , sys .executable ])
33593425 self .assertIn (b'number in executable: 5' , output )
33603426
3361- # TODO: RUSTPYTHON
3362- @unittest .expectedFailure
3427+ @unittest .expectedFailure # TODO: RUSTPYTHON
33633428 @unittest .skipUnless (sys .executable , 'sys.executable required.' )
33643429 @unittest .skipUnless (os .access ('/bin/bash' , os .X_OK ),
33653430 'Test relies on #!/bin/bash working.' )
@@ -3369,16 +3434,14 @@ def test_execute_zip64(self):
33693434 self .assertIn (b'number in executable: 5' , output )
33703435
33713436
3372- # TODO: RUSTPYTHON
3373- @unittest .skip ("TODO: RUSTPYTHON shift_jis encoding unsupported" )
33743437class EncodedMetadataTests (unittest .TestCase ):
33753438 file_names = ['\u4e00 ' , '\u4e8c ' , '\u4e09 ' ] # Han 'one', 'two', 'three'
33763439 file_content = [
33773440 "This is pure ASCII.\n " .encode ('ascii' ),
33783441 # This is modern Japanese. (UTF-8)
33793442 "\u3053 \u308c \u306f \u73fe \u4ee3 \u7684 \u65e5 \u672c \u8a9e \u3067 \u3059 \u3002 \n " .encode ('utf-8' ),
33803443 # This is obsolete Japanese. (Shift JIS)
3381- # "\u3053\u308c\u306f\u53e4\u3044\u65e5\u672c\u8a9e\u3067\u3059\u3002\n".encode('shift_jis'), # TODO: RUSTPYTHON
3444+ "\u3053 \u308c \u306f \u53e4 \u3044 \u65e5 \u672c \u8a9e \u3067 \u3059 \u3002 \n " .encode ('shift_jis' ),
33823445 ]
33833446
33843447 def setUp (self ):
0 commit comments