on master help sign in
Add unix specific integration test about running bat without any arguments
b600f62Niklas Mohrin
Cargo.lock+1
@@ -117,6 +117,7 @@ dependencies = [
117 "syntect",
117 "syntect",
118 "tempdir",
118 "tempdir",
119 "unicode-width",
119 "unicode-width",
120+ "wait-timeout",
120 "wild",
121 "wild",
121]
122]
122
123
Cargo.toml+1
@@ -76,6 +76,7 @@ default-features = false
76tempdir = "0.3"
76tempdir = "0.3"
77assert_cmd = "1.0.2"
77assert_cmd = "1.0.2"
78predicates = "1.0.6"
78predicates = "1.0.6"
79+wait-timeout = "0.2.0"
79
80
80[build-dependencies]
81[build-dependencies]
81clap = { version = "2.33", optional = true }
82clap = { version = "2.33", optional = true }
tests/integration_tests.rs+53
@@ -5,8 +5,11 @@ use std::fs::File;
5use std::path::Path;
5use std::path::Path;
6use std::process::{Command, Stdio};
6use std::process::{Command, Stdio};
7use std::str::from_utf8;
7use std::str::from_utf8;
8+use std::time::Duration;
8
9
9const EXAMPLES_DIR: &str = "tests/examples";
10const EXAMPLES_DIR: &str = "tests/examples";
11+const SAFE_CHILD_PROCESS_CREATION_TIME: Duration = Duration::from_millis(100);
12+const CHILD_WAIT_TIMEOUT: Duration = Duration::from_secs(15);
10
13
11fn bat_raw_command() -> Command {
14fn bat_raw_command() -> Command {
12 let mut cmd = Command::cargo_bin("bat").unwrap();
15 let mut cmd = Command::cargo_bin("bat").unwrap();
@@ -220,6 +223,56 @@ fn stdin_to_stdout_cycle() {
220 .failure();
223 .failure();
221}
224}
222
225
226+#[cfg(unix)]
227+#[test]
228+fn no_args_doesnt_break() {
229+ use std::io::Write;
230+ use std::os::unix::io::FromRawFd;
231+ use std::thread;
232+
233+ use clircle::nix::pty::{openpty, OpenptyResult};
234+ use wait_timeout::ChildExt;
235+
236+ // To simulate bat getting started from the shell, a process is created with stdin and stdout
237+ // as the slave end of a pseudo terminal. Although both point to the same "file", bat should
238+ // not exit, because in this case it is safe to read and write to the same fd, which is why
239+ // this test exists.
240+ let OpenptyResult { master, slave } = openpty(None, None).expect("Couldn't open pty.");
241+ let mut master = unsafe { File::from_raw_fd(master) };
242+ let stdin = unsafe { Stdio::from_raw_fd(slave) };
243+ let stdout = unsafe { Stdio::from_raw_fd(slave) };
244+
245+ let mut child = bat_raw_command()
246+ .stdin(stdin)
247+ .stdout(stdout)
248+ .spawn()
249+ .expect("Failed to start.");
250+
251+ // Some time for the child process to start and to make sure, that we can poll the exit status.
252+ // Although this waiting period is not necessary, it is best to keep it in and be absolutely
253+ // sure, that the try_wait does not error later.
254+ thread::sleep(SAFE_CHILD_PROCESS_CREATION_TIME);
255+
256+ // The child process should be running and waiting for input,
257+ // therefore no exit status should be available.
258+ let exit_status = child
259+ .try_wait()
260+ .expect("Error polling exit status, this should never happen.");
261+ assert!(exit_status.is_none());
262+
263+ // Write Ctrl-D (end of transmission) to the pty.
264+ master
265+ .write_all(&[0x04])
266+ .expect("Couldn't write EOT character to master end.");
267+
268+ let exit_status = child
269+ .wait_timeout(CHILD_WAIT_TIMEOUT)
270+ .expect("Error polling exit status, this should never happen.")
271+ .expect("Exit status not set, but the child should have exited already.");
272+
273+ assert!(exit_status.success());
274+}
275+
223#[test]
276#[test]
224fn tabs_numbers() {
277fn tabs_numbers() {
225 bat()
278 bat()