1 use std::env;
2 use std::fs::File;
3 
4 use std::io::prelude::*;
5 
6 use crate::{Exec, ExitStatus, NullFile, Redirection};
7 
8 use tempdir::TempDir;
9 
10 use crate::tests::common::read_whole_file;
11 
12 #[test]
exec_join()13 fn exec_join() {
14     let status = Exec::cmd("true").join().unwrap();
15     assert_eq!(status, ExitStatus::Exited(0));
16 }
17 
18 #[test]
null_file()19 fn null_file() {
20     let mut p = Exec::cmd("cat")
21         .stdin(NullFile)
22         .stdout(Redirection::Pipe)
23         .popen()
24         .unwrap();
25     let (out, _) = p.communicate(None).unwrap();
26     assert_eq!(out.unwrap(), "");
27 }
28 
29 #[test]
stream_stdout()30 fn stream_stdout() {
31     let stream = Exec::cmd("printf").arg("foo").stream_stdout().unwrap();
32     assert_eq!(read_whole_file(stream), "foo");
33 }
34 
35 #[test]
stream_stderr()36 fn stream_stderr() {
37     let stream = Exec::cmd("sh")
38         .args(&["-c", "printf foo >&2"])
39         .stream_stderr()
40         .unwrap();
41     assert_eq!(read_whole_file(stream), "foo");
42 }
43 
44 #[test]
stream_stdin()45 fn stream_stdin() {
46     let tmpdir = TempDir::new("test").unwrap();
47     let tmpname = tmpdir.path().join("output");
48     {
49         let mut stream = Exec::cmd("cat")
50             .stdout(File::create(&tmpname).unwrap())
51             .stream_stdin()
52             .unwrap();
53         stream.write_all(b"foo").unwrap();
54     }
55     assert_eq!(read_whole_file(File::open(&tmpname).unwrap()), "foo");
56 }
57 
58 #[test]
communicate_out()59 fn communicate_out() {
60     let mut comm = Exec::cmd("printf").arg("foo").communicate().unwrap();
61     assert_eq!(comm.read().unwrap(), (Some(b"foo".to_vec()), None));
62 }
63 
64 #[test]
communicate_in_out()65 fn communicate_in_out() {
66     let mut comm = Exec::cmd("cat").stdin("foo").communicate().unwrap();
67     assert_eq!(comm.read().unwrap(), (Some(b"foo".to_vec()), None));
68 }
69 
70 #[test]
capture_out()71 fn capture_out() {
72     let c = Exec::cmd("printf").arg("foo").capture().unwrap();
73     assert_eq!(c.stdout_str(), "foo");
74 }
75 
76 #[test]
capture_err()77 fn capture_err() {
78     let c = Exec::cmd("sh")
79         .arg("-c")
80         .arg("printf foo >&2")
81         .stderr(Redirection::Pipe)
82         .capture()
83         .unwrap();
84     assert_eq!(c.stderr_str(), "foo");
85 }
86 
87 #[test]
capture_out_with_input_data1()88 fn capture_out_with_input_data1() {
89     let c = Exec::cmd("cat").stdin("foo").capture().unwrap();
90     assert_eq!(c.stdout_str(), "foo");
91 }
92 
93 #[test]
capture_out_with_input_data2()94 fn capture_out_with_input_data2() {
95     let c = Exec::cmd("cat").stdin(b"foo".to_vec()).capture().unwrap();
96     assert_eq!(c.stdout_str(), "foo");
97 }
98 
99 #[test]
exec_shell()100 fn exec_shell() {
101     let stream = Exec::shell("printf foo").stream_stdout().unwrap();
102     assert_eq!(read_whole_file(stream), "foo");
103 }
104 
105 #[test]
pipeline_open()106 fn pipeline_open() {
107     let mut processes = { Exec::cmd("echo").arg("foo\nbar") | Exec::cmd("wc").arg("-l") }
108         .stdout(Redirection::Pipe)
109         .popen()
110         .unwrap();
111     let (output, _) = processes[1].communicate(None).unwrap();
112     assert_eq!(output.unwrap().trim(), "2");
113 }
114 
115 #[test]
pipeline_stream_out()116 fn pipeline_stream_out() {
117     let stream = { Exec::cmd("echo").arg("foo\nbar") | Exec::cmd("wc").arg("-l") }
118         .stream_stdout()
119         .unwrap();
120     assert_eq!(read_whole_file(stream).trim(), "2");
121 }
122 
123 #[test]
pipeline_stream_in()124 fn pipeline_stream_in() {
125     let tmpdir = TempDir::new("test").unwrap();
126     let tmpname = tmpdir.path().join("output");
127     {
128         let mut stream = { Exec::cmd("cat") | Exec::cmd("wc").arg("-l") }
129             .stdout(File::create(&tmpname).unwrap())
130             .stream_stdin()
131             .unwrap();
132         stream.write_all(b"foo\nbar\nbaz\n").unwrap();
133     }
134     assert_eq!(read_whole_file(File::open(&tmpname).unwrap()).trim(), "3");
135 }
136 
137 #[test]
pipeline_compose_pipelines()138 fn pipeline_compose_pipelines() {
139     let pipe1 = Exec::cmd("echo").arg("foo\nbar\nfoo") | Exec::cmd("sort");
140     let pipe2 = Exec::cmd("uniq") | Exec::cmd("wc").arg("-l");
141     let pipe = pipe1 | pipe2;
142     let stream = pipe.stream_stdout().unwrap();
143     assert_eq!(read_whole_file(stream).trim(), "2");
144 }
145 
146 trait Crlf {
to_crlf(self) -> Vec<u8>147     fn to_crlf(self) -> Vec<u8>;
148 }
149 impl Crlf for Vec<u8> {
150     #[cfg(windows)]
to_crlf(self) -> Vec<u8>151     fn to_crlf(self) -> Vec<u8> {
152         self.iter()
153             .flat_map(|&c| {
154                 if c == b'\n' {
155                     vec![b'\r', b'\n']
156                 } else {
157                     vec![c]
158                 }
159             })
160             .collect()
161     }
162     #[cfg(unix)]
to_crlf(self) -> Vec<u8>163     fn to_crlf(self) -> Vec<u8> {
164         self
165     }
166 }
167 
168 #[test]
pipeline_communicate_out()169 fn pipeline_communicate_out() {
170     let pipe1 = Exec::cmd("echo").arg("foo\nbar\nfoo") | Exec::cmd("sort");
171     let mut comm = pipe1.communicate().unwrap();
172     assert_eq!(
173         comm.read().unwrap(),
174         (Some(b"bar\nfoo\nfoo\n".to_vec().to_crlf()), Some(vec![]))
175     );
176 }
177 
178 #[test]
pipeline_communicate_in_out()179 fn pipeline_communicate_in_out() {
180     let pipe1 = Exec::cmd("grep").arg("foo") | Exec::cmd("sort");
181     let mut comm = pipe1.stdin("foobar\nbaz\nfoo\n").communicate().unwrap();
182     let (out, _err) = comm.read().unwrap();
183     assert_eq!(out, Some(b"foo\nfoobar\n".to_vec().to_crlf()));
184 }
185 
186 #[test]
pipeline_capture()187 fn pipeline_capture() {
188     let c = { Exec::cmd("cat") | Exec::shell("wc -l") }
189         .stdin("foo\nbar\nbaz\n")
190         .capture()
191         .unwrap();
192     assert_eq!(c.stdout_str().trim(), "3");
193     assert_eq!(c.stderr_str().trim(), "");
194 }
195 
196 #[test]
pipeline_capture_error_1()197 fn pipeline_capture_error_1() {
198     let c = {
199         Exec::cmd("sh")
200             .arg("-c")
201             .arg("echo foo >&2; printf 'bar\nbaz\n'")
202             | Exec::shell("wc -l")
203     }
204     .capture()
205     .unwrap();
206     assert_eq!(c.stdout_str().trim(), "2");
207     assert_eq!(c.stderr_str().trim(), "foo");
208 }
209 
210 #[test]
pipeline_capture_error_2()211 fn pipeline_capture_error_2() {
212     let c = {
213         Exec::cmd("cat")
214             | Exec::cmd("sh")
215                 .arg("-c")
216                 .arg("cat; echo foo >&2; printf 'four\nfive\n'")
217             | Exec::cmd("sh").arg("-c").arg("echo bar >&2; cat")
218             | Exec::shell("wc -l")
219     }
220     .stdin("one\ntwo\nthree\n")
221     .capture()
222     .unwrap();
223     assert_eq!(c.stdout_str().trim(), "5");
224     assert!(
225         c.stderr_str().trim() == "foo\nbar" || c.stderr_str().trim() == "bar\nfoo",
226         "got {:?}",
227         c.stderr_str()
228     );
229 }
230 
231 #[test]
pipeline_join()232 fn pipeline_join() {
233     let status = (Exec::cmd("true") | Exec::cmd("true")).join().unwrap();
234     assert_eq!(status, ExitStatus::Exited(0));
235 
236     let status = (Exec::cmd("false") | Exec::cmd("true")).join().unwrap();
237     assert_eq!(status, ExitStatus::Exited(0));
238 
239     let status = (Exec::cmd("true") | Exec::cmd("false")).join().unwrap();
240     assert_eq!(status, ExitStatus::Exited(1));
241 }
242 
243 #[test]
pipeline_invalid_1()244 fn pipeline_invalid_1() {
245     let p = (Exec::cmd("echo").arg("foo") | Exec::cmd("no-such-command")).join();
246     assert!(p.is_err());
247 }
248 
249 #[test]
pipeline_invalid_2()250 fn pipeline_invalid_2() {
251     let p = (Exec::cmd("no-such-command") | Exec::cmd("echo").arg("foo")).join();
252     assert!(p.is_err());
253 }
254 
255 #[test]
256 #[should_panic]
reject_input_data_popen()257 fn reject_input_data_popen() {
258     Exec::cmd("true").stdin("xxx").popen().unwrap();
259 }
260 
261 #[test]
262 #[should_panic]
reject_input_data_join()263 fn reject_input_data_join() {
264     Exec::cmd("true").stdin("xxx").join().unwrap();
265 }
266 
267 #[test]
268 #[should_panic]
reject_input_data_stream_stdout()269 fn reject_input_data_stream_stdout() {
270     Exec::cmd("true").stdin("xxx").stream_stdout().unwrap();
271 }
272 
273 #[test]
274 #[should_panic]
reject_input_data_stream_stderr()275 fn reject_input_data_stream_stderr() {
276     Exec::cmd("true").stdin("xxx").stream_stderr().unwrap();
277 }
278 
279 #[test]
280 #[should_panic]
reject_input_data_stream_stdin()281 fn reject_input_data_stream_stdin() {
282     Exec::cmd("true").stdin("xxx").stream_stdin().unwrap();
283 }
284 
285 #[test]
env_set()286 fn env_set() {
287     assert!(Exec::cmd("sh")
288         .args(&["-c", r#"test "$SOMEVAR" = "foo""#])
289         .env("SOMEVAR", "foo")
290         .join()
291         .unwrap()
292         .success());
293 }
294 
295 #[test]
env_extend()296 fn env_extend() {
297     assert!(Exec::cmd("sh")
298         .args(&["-c", r#"test "$VAR1" = "foo" && test "$VAR2" = "bar""#])
299         .env_extend(&[("VAR1", "foo"), ("VAR2", "bar")])
300         .join()
301         .unwrap()
302         .success());
303 }
304 
305 #[test]
env_inherit()306 fn env_inherit() {
307     // use a unique name to avoid interference with other tests
308     let varname = "TEST_ENV_INHERIT_VARNAME";
309     env::set_var(varname, "inherited");
310     assert!(Exec::cmd("sh")
311         .args(&["-c", &format!(r#"test "${}" = "inherited""#, varname)])
312         .join()
313         .unwrap()
314         .success());
315     env::remove_var(varname);
316 }
317 
318 #[test]
env_inherit_set()319 fn env_inherit_set() {
320     // use a unique name to avoid interference with other tests
321     let varname = "TEST_ENV_INHERIT_SET_VARNAME";
322     env::set_var(varname, "inherited");
323     assert!(Exec::cmd("sh")
324         .args(&["-c", &format!(r#"test "${}" = "new""#, varname)])
325         .env(varname, "new")
326         .join()
327         .unwrap()
328         .success());
329     env::remove_var(varname);
330 }
331 
332 #[test]
exec_to_string()333 fn exec_to_string() {
334     let cmd = Exec::cmd("sh")
335         .arg("arg1")
336         .arg("don't")
337         .arg("arg3 arg4")
338         .arg("?")
339         .arg(" ") // regular space
340         .arg("\u{009c}"); // STRING TERMINATOR
341     assert_eq!(
342         format!("{:?}", cmd),
343         "Exec { sh arg1 'don'\\''t' 'arg3 arg4' '?' ' ' '\u{009c}' }"
344     )
345 }
346 
347 #[test]
pipeline_to_string()348 fn pipeline_to_string() {
349     let pipeline = { Exec::cmd("command with space").arg("arg") | Exec::cmd("wc").arg("-l") };
350     assert_eq!(
351         format!("{:?}", pipeline),
352         "Pipeline { 'command with space' arg | wc -l }"
353     )
354 }
355