@@ -20,3 +20,190 @@ pub use linux::*;
2020pub mod other;
2121#[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
2222pub use other:: copy_stream;
23+
24+ #[ cfg( test) ]
25+ mod tests {
26+ use super :: * ;
27+ use std:: fs:: File ;
28+ use tempfile:: tempdir;
29+
30+ #[ cfg( unix) ]
31+ use crate :: pipes;
32+ #[ cfg( unix) ]
33+ use std:: fs:: OpenOptions ;
34+ #[ cfg( unix) ]
35+ use std:: {
36+ io:: { Seek , SeekFrom } ,
37+ thread,
38+ } ;
39+
40+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
41+ use nix:: unistd;
42+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
43+ use std:: os:: fd:: AsRawFd ;
44+
45+ use std:: io:: { Read , Write } ;
46+
47+ #[ cfg( unix) ]
48+ fn new_temp_file ( ) -> File {
49+ let temp_dir = tempdir ( ) . unwrap ( ) ;
50+ OpenOptions :: new ( )
51+ . read ( true )
52+ . write ( true )
53+ . create ( true )
54+ . open ( temp_dir. path ( ) . join ( "file.txt" ) )
55+ . unwrap ( )
56+ }
57+
58+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
59+ #[ test]
60+ fn test_file_is_pipe ( ) {
61+ let temp_file = new_temp_file ( ) ;
62+ let ( pipe_read, pipe_write) = pipes:: pipe ( ) . unwrap ( ) ;
63+
64+ assert ! ( is_pipe( & pipe_read) . unwrap( ) ) ;
65+ assert ! ( is_pipe( & pipe_write) . unwrap( ) ) ;
66+ assert ! ( !is_pipe( & temp_file) . unwrap( ) ) ;
67+ }
68+
69+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
70+ #[ test]
71+ fn test_valid_splice_errs ( ) {
72+ use nix:: errno:: Errno ;
73+ use nix:: Error ;
74+
75+ let err = Error :: from ( Errno :: EINVAL ) ;
76+ assert_eq ! ( maybe_unsupported( err) . unwrap( ) , ( 0 , true ) ) ;
77+
78+ let err = Error :: from ( Errno :: ENOSYS ) ;
79+ assert_eq ! ( maybe_unsupported( err) . unwrap( ) , ( 0 , true ) ) ;
80+
81+ let err = Error :: from ( Errno :: EBADF ) ;
82+ assert_eq ! ( maybe_unsupported( err) . unwrap( ) , ( 0 , true ) ) ;
83+
84+ let err = Error :: from ( Errno :: EPERM ) ;
85+ assert ! ( maybe_unsupported( err) . is_err( ) ) ;
86+ }
87+
88+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
89+ #[ test]
90+ fn test_splice_data_to_pipe ( ) {
91+ let ( pipe_read, pipe_write) = pipes:: pipe ( ) . unwrap ( ) ;
92+ let data = b"Hello, world!" ;
93+ let ( bytes, _) = splice_data_to_pipe ( data, & pipe_write) . unwrap ( ) ;
94+ let mut buf = [ 0 ; 1024 ] ;
95+ let n = unistd:: read ( pipe_read. as_raw_fd ( ) , & mut buf) . unwrap ( ) ;
96+ assert_eq ! ( & buf[ ..n] , data) ;
97+ assert_eq ! ( bytes as usize , data. len( ) ) ;
98+ }
99+
100+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
101+ #[ test]
102+ fn test_splice_data_to_file ( ) {
103+ use std:: io:: { Read , Seek , SeekFrom } ;
104+
105+ let mut temp_file = new_temp_file ( ) ;
106+ let ( pipe_read, pipe_write) = pipes:: pipe ( ) . unwrap ( ) ;
107+ let data = b"Hello, world!" ;
108+ let ( bytes, _) = splice_data_to_fd ( data, & pipe_read, & pipe_write, & temp_file) . unwrap ( ) ;
109+ assert_eq ! ( bytes as usize , data. len( ) ) ;
110+
111+ // We would have been at the end already, so seek again to the start.
112+ temp_file. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
113+
114+ let mut buf = Vec :: new ( ) ;
115+ temp_file. read_to_end ( & mut buf) . unwrap ( ) ;
116+ assert_eq ! ( buf, data) ;
117+ }
118+
119+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
120+ #[ test]
121+ fn test_copy_exact ( ) {
122+ let ( mut pipe_read, mut pipe_write) = pipes:: pipe ( ) . unwrap ( ) ;
123+ let data = b"Hello, world!" ;
124+ let n = pipe_write. write ( data) . unwrap ( ) ;
125+ assert_eq ! ( n, data. len( ) ) ;
126+ let mut buf = [ 0 ; 1024 ] ;
127+ let n = copy_exact ( pipe_read. as_raw_fd ( ) , & pipe_write, data. len ( ) ) . unwrap ( ) ;
128+ let n2 = pipe_read. read ( & mut buf) . unwrap ( ) ;
129+ assert_eq ! ( n, n2) ;
130+ assert_eq ! ( & buf[ ..n] , data) ;
131+ }
132+
133+ #[ test]
134+ #[ cfg( unix) ]
135+ fn test_copy_stream ( ) {
136+ let mut dest_file = new_temp_file ( ) ;
137+
138+ let ( mut pipe_read, mut pipe_write) = pipes:: pipe ( ) . unwrap ( ) ;
139+ let data = b"Hello, world!" ;
140+ let thread = thread:: spawn ( move || {
141+ pipe_write. write_all ( data) . unwrap ( ) ;
142+ } ) ;
143+ let result = copy_stream ( & mut pipe_read, & mut dest_file) . unwrap ( ) ;
144+ thread. join ( ) . unwrap ( ) ;
145+ assert ! ( result == data. len( ) as u64 ) ;
146+
147+ // We would have been at the end already, so seek again to the start.
148+ dest_file. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
149+
150+ let mut buf = Vec :: new ( ) ;
151+ dest_file. read_to_end ( & mut buf) . unwrap ( ) ;
152+
153+ assert_eq ! ( buf, data) ;
154+ }
155+
156+ #[ test]
157+ #[ cfg( not( unix) ) ]
158+ // Test for non-unix platforms. We use regular files instead.
159+ fn test_copy_stream ( ) {
160+ let temp_dir = tempdir ( ) . unwrap ( ) ;
161+ let src_path = temp_dir. path ( ) . join ( "src.txt" ) ;
162+ let dest_path = temp_dir. path ( ) . join ( "dest.txt" ) ;
163+
164+ let mut src_file = File :: create ( & src_path) . unwrap ( ) ;
165+ let mut dest_file = File :: create ( & dest_path) . unwrap ( ) ;
166+
167+ let data = b"Hello, world!" ;
168+ src_file. write_all ( data) . unwrap ( ) ;
169+ src_file. sync_all ( ) . unwrap ( ) ;
170+
171+ let mut src_file = File :: open ( & src_path) . unwrap ( ) ;
172+ let bytes_copied = copy_stream ( & mut src_file, & mut dest_file) . unwrap ( ) ;
173+
174+ let mut dest_file = File :: open ( & dest_path) . unwrap ( ) ;
175+ let mut buf = Vec :: new ( ) ;
176+ dest_file. read_to_end ( & mut buf) . unwrap ( ) ;
177+
178+ assert_eq ! ( bytes_copied as usize , data. len( ) ) ;
179+ assert_eq ! ( buf, data) ;
180+ }
181+
182+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
183+ #[ test]
184+ fn test_splice_write ( ) {
185+ use std:: {
186+ io:: { Read , Seek , SeekFrom , Write } ,
187+ thread,
188+ } ;
189+
190+ let ( pipe_read, mut pipe_write) = pipes:: pipe ( ) . unwrap ( ) ;
191+ let mut dest_file = new_temp_file ( ) ;
192+ let data = b"Hello, world!" ;
193+ let thread = thread:: spawn ( move || {
194+ pipe_write. write_all ( data) . unwrap ( ) ;
195+ } ) ;
196+ let ( bytes, _) = splice_write ( & pipe_read, & dest_file) . unwrap ( ) ;
197+ thread. join ( ) . unwrap ( ) ;
198+
199+ assert ! ( bytes == data. len( ) as u64 ) ;
200+
201+ // We would have been at the end already, so seek again to the start.
202+ dest_file. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
203+
204+ let mut buf = Vec :: new ( ) ;
205+ dest_file. read_to_end ( & mut buf) . unwrap ( ) ;
206+
207+ assert_eq ! ( buf, data) ;
208+ }
209+ }
0 commit comments