@@ -381,6 +381,123 @@ def test_copy_file_range_offset(self):
381
381
self .assertEqual (read [out_seek :],
382
382
data [in_skip :in_skip + i ])
383
383
384
+ @unittest .skipUnless (hasattr (os , 'splice' ), 'test needs os.splice()' )
385
+ def test_splice_invalid_values (self ):
386
+ with self .assertRaises (ValueError ):
387
+ os .splice (0 , 1 , - 10 )
388
+
389
+ @unittest .skipUnless (hasattr (os , 'splice' ), 'test needs os.splice()' )
390
+ def test_splice (self ):
391
+ TESTFN2 = os_helper .TESTFN + ".3"
392
+ data = b'0123456789'
393
+
394
+ create_file (os_helper .TESTFN , data )
395
+ self .addCleanup (os_helper .unlink , os_helper .TESTFN )
396
+
397
+ in_file = open (os_helper .TESTFN , 'rb' )
398
+ self .addCleanup (in_file .close )
399
+ in_fd = in_file .fileno ()
400
+
401
+ read_fd , write_fd = os .pipe ()
402
+ self .addCleanup (lambda : os .close (read_fd ))
403
+ self .addCleanup (lambda : os .close (write_fd ))
404
+
405
+ try :
406
+ i = os .splice (in_fd , write_fd , 5 )
407
+ except OSError as e :
408
+ # Handle the case in which Python was compiled
409
+ # in a system with the syscall but without support
410
+ # in the kernel.
411
+ if e .errno != errno .ENOSYS :
412
+ raise
413
+ self .skipTest (e )
414
+ else :
415
+ # The number of copied bytes can be less than
416
+ # the number of bytes originally requested.
417
+ self .assertIn (i , range (0 , 6 ));
418
+
419
+ self .assertEqual (os .read (read_fd , 100 ), data [:i ])
420
+
421
+ @unittest .skipUnless (hasattr (os , 'splice' ), 'test needs os.splice()' )
422
+ def test_splice_offset_in (self ):
423
+ TESTFN4 = os_helper .TESTFN + ".4"
424
+ data = b'0123456789'
425
+ bytes_to_copy = 6
426
+ in_skip = 3
427
+
428
+ create_file (os_helper .TESTFN , data )
429
+ self .addCleanup (os_helper .unlink , os_helper .TESTFN )
430
+
431
+ in_file = open (os_helper .TESTFN , 'rb' )
432
+ self .addCleanup (in_file .close )
433
+ in_fd = in_file .fileno ()
434
+
435
+ read_fd , write_fd = os .pipe ()
436
+ self .addCleanup (lambda : os .close (read_fd ))
437
+ self .addCleanup (lambda : os .close (write_fd ))
438
+
439
+ try :
440
+ i = os .splice (in_fd , write_fd , bytes_to_copy , offset_src = in_skip )
441
+ except OSError as e :
442
+ # Handle the case in which Python was compiled
443
+ # in a system with the syscall but without support
444
+ # in the kernel.
445
+ if e .errno != errno .ENOSYS :
446
+ raise
447
+ self .skipTest (e )
448
+ else :
449
+ # The number of copied bytes can be less than
450
+ # the number of bytes originally requested.
451
+ self .assertIn (i , range (0 , bytes_to_copy + 1 ));
452
+
453
+ read = os .read (read_fd , 100 )
454
+ # 012 are skipped (in_skip)
455
+ # 345678 are copied in the file (in_skip + bytes_to_copy)
456
+ self .assertEqual (read , data [in_skip :in_skip + i ])
457
+
458
+ @unittest .skipUnless (hasattr (os , 'splice' ), 'test needs os.splice()' )
459
+ def test_splice_offset_out (self ):
460
+ TESTFN4 = os_helper .TESTFN + ".4"
461
+ data = b'0123456789'
462
+ bytes_to_copy = 6
463
+ out_seek = 3
464
+
465
+ create_file (os_helper .TESTFN , data )
466
+ self .addCleanup (os_helper .unlink , os_helper .TESTFN )
467
+
468
+ read_fd , write_fd = os .pipe ()
469
+ self .addCleanup (lambda : os .close (read_fd ))
470
+ self .addCleanup (lambda : os .close (write_fd ))
471
+ os .write (write_fd , data )
472
+
473
+ out_file = open (TESTFN4 , 'w+b' )
474
+ self .addCleanup (os_helper .unlink , TESTFN4 )
475
+ self .addCleanup (out_file .close )
476
+ out_fd = out_file .fileno ()
477
+
478
+ try :
479
+ i = os .splice (read_fd , out_fd , bytes_to_copy , offset_dst = out_seek )
480
+ except OSError as e :
481
+ # Handle the case in which Python was compiled
482
+ # in a system with the syscall but without support
483
+ # in the kernel.
484
+ if e .errno != errno .ENOSYS :
485
+ raise
486
+ self .skipTest (e )
487
+ else :
488
+ # The number of copied bytes can be less than
489
+ # the number of bytes originally requested.
490
+ self .assertIn (i , range (0 , bytes_to_copy + 1 ));
491
+
492
+ with open (TESTFN4 , 'rb' ) as in_file :
493
+ read = in_file .read ()
494
+ # seeked bytes (5) are zero'ed
495
+ self .assertEqual (read [:out_seek ], b'\x00 ' * out_seek )
496
+ # 012 are skipped (in_skip)
497
+ # 345678 are copied in the file (in_skip + bytes_to_copy)
498
+ self .assertEqual (read [out_seek :], data [:i ])
499
+
500
+
384
501
# Test attributes on return values from os.*stat* family.
385
502
class StatAttributeTests (unittest .TestCase ):
386
503
def setUp (self ):
0 commit comments