@@ -3447,6 +3447,100 @@ def test_too_short(self):
3447
3447
self .assertEqual (
3448
3448
b"zzz" , zipfile ._Extra .strip (b"zzz" , (self .ZIP64_EXTRA ,)))
3449
3449
3450
+ class StoreSeekReadTest (unittest .TestCase ):
3451
+ def test_store_seek_read (self ):
3452
+ class StatIO (io .RawIOBase ):
3453
+ def __init__ (self , buf : bytes ):
3454
+ self .bytes_read = 0
3455
+ self .buffer = buf
3456
+ self .pos = 0
3457
+ self .eof = False
3458
+
3459
+ def readinto (self , buffer , / ):
3460
+ if self .eof :
3461
+ return 0
3462
+ sz = min (len (buffer ), len (self .buffer ) - self .pos )
3463
+ buffer [:sz ] = self .buffer [self .pos :self .pos + sz ]
3464
+ self .pos += sz
3465
+ self .bytes_read += sz
3466
+ self .eof = self .pos == len (self .buffer )
3467
+ return sz
3468
+
3469
+ def readall (self ):
3470
+ if self .eof :
3471
+ return b''
3472
+ self .eof = True
3473
+ self .bytes_read += len (self .buffer ) - self .pos
3474
+ ret = self .buffer [self .pos :]
3475
+ self .pos = len (self .buffer )
3476
+ return ret
3477
+
3478
+ def seek (self , offset , whence = os .SEEK_SET , / ):
3479
+ if whence == os .SEEK_CUR :
3480
+ new_pos = self .pos + offset
3481
+ elif whence == os .SEEK_SET :
3482
+ new_pos = offset
3483
+ elif whence == os .SEEK_END :
3484
+ new_pos = len (self .buffer ) + offset
3485
+ else :
3486
+ raise ValueError ("unsupported whence" )
3487
+
3488
+ if new_pos < 0 :
3489
+ new_pos = 0
3490
+ elif new_pos > len (self .buffer ):
3491
+ new_pos = len (self .buffer )
3492
+
3493
+ self .eof = new_pos == len (self .buffer )
3494
+ self .pos = new_pos
3495
+ return new_pos
3496
+
3497
+ def tell (self ):
3498
+ return self .pos
3499
+
3500
+ def readable (self ):
3501
+ return True
3502
+
3503
+ def writable (self ):
3504
+ return False
3505
+
3506
+ def seekable (self ):
3507
+ return True
3508
+
3509
+ def get_bytes_read (self ):
3510
+ return self .bytes_read
3511
+
3512
+ bio = io .BytesIO ()
3513
+ txt = b'0123456789' * 10000
3514
+
3515
+ # Check seek on a file
3516
+ with zipfile .ZipFile (bio , "w" ) as zipf :
3517
+ zipf .writestr ("foo.txt" , txt ) # 100000 bytes
3518
+
3519
+ sio = StatIO (bio .getvalue ())
3520
+ with zipfile .ZipFile (sio , "r" ) as zipf :
3521
+ with zipf .open ("foo.txt" , "r" ) as fp :
3522
+ br = sio .get_bytes_read ()
3523
+ fp .seek (50000 , os .SEEK_CUR )
3524
+ self .assertEqual (sio .get_bytes_read () - br , 0 , 'seek produces extra read!' )
3525
+
3526
+ b = fp .read (100 )
3527
+ self .assertEqual (b , txt [:100 ])
3528
+
3529
+ # backward seek
3530
+ # seek length must be more than MIN_READ_SIZE (4096)
3531
+ br = sio .get_bytes_read ()
3532
+ fp .seek (5000 , os .SEEK_CUR )
3533
+ b = fp .read (100 )
3534
+ self .assertEqual (b , txt [50000 :50100 ])
3535
+ self .assertLessEqual (sio .get_bytes_read () - br , 4096 , 'read more bytes after backward seek!' )
3536
+
3537
+ # forward seek
3538
+ # seek length must be more than MIN_READ_SIZE (4096)
3539
+ br = sio .get_bytes_read ()
3540
+ fp .seek (- 40000 , os .SEEK_CUR )
3541
+ b = fp .read (100 )
3542
+ self .assertEqual (b , txt [10100 :10200 ])
3543
+ self .assertLessEqual (sio .get_bytes_read () - br , 4096 , 'read more bytes after forward seek!' )
3450
3544
3451
3545
if __name__ == "__main__" :
3452
3546
unittest .main ()
0 commit comments