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