@@ -1,28 +1,37 @@
1−use assert_cmd::assert::OutputAssertExt;
2use assert_cmd::cargo::CommandCargoExt;
1use assert_cmd::cargo::CommandCargoExt;
3use predicates::{prelude::predicate, str::PredicateStrExt};
2use predicates::{prelude::predicate, str::PredicateStrExt};
4use serial_test::serial;
3use serial_test::serial;
6use std::path::Path;
4use std::path::Path;
7−use std::process::{Command, Stdio};
5+use std::process::Command;
8use std::str::from_utf8;
6use std::str::from_utf8;
9use tempfile::tempdir;
7use tempfile::tempdir;
11#[cfg(unix)]
9#[cfg(unix)]
11+ pub use std::fs::File;
12+ pub use std::io::{self, Write};
13+ pub use std::os::unix::io::FromRawFd;
14+ pub use std::path::PathBuf;
15+ pub use std::process::Stdio;
12−use std::time::Duration;
17+ pub use std::time::Duration;
19+ pub use assert_cmd::assert::OutputAssertExt;
20+ pub use nix::pty::{openpty, OpenptyResult};
21+ pub use wait_timeout::ChildExt;
23+ pub const SAFE_CHILD_PROCESS_CREATION_TIME: Duration = Duration::from_millis(100);
24+ pub const CHILD_WAIT_TIMEOUT: Duration = Duration::from_secs(15);
15use utils::mocked_pagers;
30use utils::mocked_pagers;
17const EXAMPLES_DIR: &str = "tests/examples";
32const EXAMPLES_DIR: &str = "tests/examples";
19−#[cfg(unix)]
34+fn bat_raw_command_with_config() -> Command {
20−const SAFE_CHILD_PROCESS_CREATION_TIME: Duration = Duration::from_millis(100);
23−const CHILD_WAIT_TIMEOUT: Duration = Duration::from_secs(15);
25−fn bat_raw_command() -> Command {
26 let mut cmd = Command::cargo_bin("bat").unwrap();
35 let mut cmd = Command::cargo_bin("bat").unwrap();
27 cmd.current_dir("tests/examples");
36 cmd.current_dir("tests/examples");
28 cmd.env_remove("PAGER");
37 cmd.env_remove("PAGER");
@@ -34,14 +43,18 @@ fn bat_raw_command() -> Command {
46+fn bat_raw_command() -> Command {
47+ let mut cmd = bat_raw_command_with_config();
48+ cmd.arg("--no-config");
37fn bat_with_config() -> assert_cmd::Command {
52fn bat_with_config() -> assert_cmd::Command {
38− assert_cmd::Command::from_std(bat_raw_command())
53+ assert_cmd::Command::from_std(bat_raw_command_with_config())
41fn bat() -> assert_cmd::Command {
56fn bat() -> assert_cmd::Command {
42− let mut cmd = bat_with_config();
57+ assert_cmd::Command::from_std(bat_raw_command())
43− cmd.arg("--no-config");
@@ -210,40 +223,82 @@ fn line_range_multiple() {
210 .stdout("line 1\nline 2\nline 4\n");
223 .stdout("line 1\nline 2\nline 4\n");
227+fn setup_temp_file(content: &[u8]) -> io::Result<(PathBuf, tempfile::TempDir)> {
228+ let dir = tempfile::tempdir().expect("Couldn't create tempdir");
229+ let path = dir.path().join("temp_file");
230+ File::create(&path)?.write_all(content)?;
214−fn basic_io_cycle() {
236+fn basic_io_cycle() -> io::Result<()> {
237+ let (filename, dir) = setup_temp_file(b"I am not empty")?;
215− let file_out = Stdio::from(File::open("tests/examples/cycle.txt").unwrap());
239+ let file_out = Stdio::from(File::create(&filename)?);
216− bat_raw_command()
240+ let res = bat_raw_command()
217 .arg("test.txt")
241 .arg("test.txt")
218− .arg("cycle.txt")
242+ .arg(&filename)
219 .stdout(file_out)
243 .stdout(file_out)
220− .assert()
244+ .assert();
221− .failure();
246+ res.failure();
225−fn stdin_to_stdout_cycle() {
252+fn first_file_cyclic_is_ok() -> io::Result<()> {
253+ let (filename, dir) = setup_temp_file(b"I am not empty")?;
226− let file_out = Stdio::from(File::open("tests/examples/cycle.txt").unwrap());
255+ let file_out = Stdio::from(File::create(&filename)?);
227− let file_in = Stdio::from(File::open("tests/examples/cycle.txt").unwrap());
228− bat_raw_command()
256+ let res = bat_raw_command()
229− .stdin(file_in)
257+ .arg(&filename)
230 .arg("test.txt")
258 .arg("test.txt")
232 .stdout(file_out)
259 .stdout(file_out)
233− .assert()
260+ .assert();
234− .failure();
261+ drop(dir);
237#[cfg(unix)]
266#[cfg(unix)]
239−fn no_args_doesnt_break() {
268+fn empty_file_cycle_is_ok() -> io::Result<()> {
240− use std::io::Write;
269+ let (filename, dir) = setup_temp_file(b"I am not empty")?;
241− use std::os::unix::io::FromRawFd;
270+
242− use std::thread;
271+ let file_out = Stdio::from(File::create(&filename)?);
272+ let res = bat_raw_command()
244− use clircle::nix::pty::{openpty, OpenptyResult};
282+#[cfg(unix)]
245− use wait_timeout::ChildExt;
283+#[test]
284+fn stdin_to_stdout_cycle() -> io::Result<()> {
285+ let (filename, dir) = setup_temp_file(b"I am not empty")?;
286+ let file_in = Stdio::from(File::open(&filename)?);
287+ let file_out = Stdio::from(File::create(&filename)?);
288+ let res = bat_raw_command()
301+fn no_args_doesnt_break() {
247 // To simulate bat getting started from the shell, a process is created with stdin and stdout
302 // To simulate bat getting started from the shell, a process is created with stdin and stdout
248 // as the slave end of a pseudo terminal. Although both point to the same "file", bat should
303 // as the slave end of a pseudo terminal. Although both point to the same "file", bat should
249 // not exit, because in this case it is safe to read and write to the same fd, which is why
304 // not exit, because in this case it is safe to read and write to the same fd, which is why