1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

tests/tail: Fix tests to reflect changes from the refactoring #3905

This commit is contained in:
Joining7943 2022-09-21 22:10:15 +02:00 committed by Sylvestre Ledru
parent e523a56dab
commit 1725151ef8
2 changed files with 899 additions and 792 deletions

View file

@ -11,24 +11,23 @@ extern crate tail;
use crate::common::random::*; use crate::common::random::*;
use crate::common::util::*; use crate::common::util::*;
use rand::distributions::Alphanumeric;
use std::char::from_digit; use std::char::from_digit;
#[cfg(unix)]
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::process::Stdio; use std::process::Stdio;
#[cfg(unix)]
use std::thread::sleep; use std::thread::sleep;
#[cfg(unix)]
use std::time::Duration; use std::time::Duration;
use tail::chunks::BUFFER_SIZE as CHUNK_BUFFER_SIZE;
static FOOBAR_TXT: &str = "foobar.txt"; static FOOBAR_TXT: &str = "foobar.txt";
static FOOBAR_2_TXT: &str = "foobar2.txt"; static FOOBAR_2_TXT: &str = "foobar2.txt";
static FOOBAR_WITH_NULL_TXT: &str = "foobar_with_null.txt"; static FOOBAR_WITH_NULL_TXT: &str = "foobar_with_null.txt";
#[cfg(unix)] #[allow(dead_code)]
static FOLLOW_NAME_TXT: &str = "follow_name.txt"; static FOLLOW_NAME_TXT: &str = "follow_name.txt";
#[cfg(unix)] #[allow(dead_code)]
static FOLLOW_NAME_SHORT_EXP: &str = "follow_name_short.expected"; static FOLLOW_NAME_SHORT_EXP: &str = "follow_name_short.expected";
#[cfg(target_os = "linux")] #[allow(dead_code)]
static FOLLOW_NAME_EXP: &str = "follow_name.expected"; static FOLLOW_NAME_EXP: &str = "follow_name.expected";
#[test] #[test]
@ -37,7 +36,6 @@ fn test_invalid_arg() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_stdin_default() { fn test_stdin_default() {
new_ucmd!() new_ucmd!()
.pipe_in_fixture(FOOBAR_TXT) .pipe_in_fixture(FOOBAR_TXT)
@ -47,7 +45,6 @@ fn test_stdin_default() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_stdin_explicit() { fn test_stdin_explicit() {
new_ucmd!() new_ucmd!()
.pipe_in_fixture(FOOBAR_TXT) .pipe_in_fixture(FOOBAR_TXT)
@ -58,7 +55,7 @@ fn test_stdin_explicit() {
} }
#[test] #[test]
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux #[cfg(not(target_vendor = "apple"))] // FIXME: for currently not working platforms
fn test_stdin_redirect_file() { fn test_stdin_redirect_file() {
// $ echo foo > f // $ echo foo > f
@ -93,7 +90,12 @@ fn test_stdin_redirect_file() {
.run_no_wait(); .run_no_wait();
sleep(Duration::from_millis(500)); sleep(Duration::from_millis(500));
p.kill().unwrap();
// Cleanup the process if it is still running. The result isn't important
// for the test, so it is ignored.
// NOTE: The result may be Error on windows with an Os error `Permission
// Denied` if the process already terminated:
let _ = p.kill();
let (buf_stdout, buf_stderr) = take_stdout_stderr(&mut p); let (buf_stdout, buf_stderr) = take_stdout_stderr(&mut p);
assert!(buf_stdout.eq("foo")); assert!(buf_stdout.eq("foo"));
@ -101,7 +103,7 @@ fn test_stdin_redirect_file() {
} }
#[test] #[test]
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux #[cfg(not(target_vendor = "apple"))] // FIXME: for currently not working platforms
fn test_stdin_redirect_offset() { fn test_stdin_redirect_offset() {
// inspired by: "gnu/tests/tail-2/start-middle.sh" // inspired by: "gnu/tests/tail-2/start-middle.sh"
use std::io::{Seek, SeekFrom}; use std::io::{Seek, SeekFrom};
@ -122,8 +124,12 @@ fn test_stdin_redirect_offset() {
} }
#[test] #[test]
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux #[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] // FIXME: for currently not working platforms
fn test_stdin_redirect_offset2() { fn test_stdin_redirect_offset2() {
// FIXME: windows: Failed because of difference in printed header. See below.
// actual : ==> - <==
// expected: ==> standard input <==
// like test_stdin_redirect_offset but with multiple files // like test_stdin_redirect_offset but with multiple files
use std::io::{Seek, SeekFrom}; use std::io::{Seek, SeekFrom};
@ -197,8 +203,9 @@ fn test_nc_0_wo_follow2() {
.succeeded(); .succeeded();
} }
// TODO: Add similar test for windows
#[test] #[test]
#[cfg(all(unix, not(target_os = "freebsd")))] #[cfg(unix)]
fn test_permission_denied() { fn test_permission_denied() {
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
let at = &ts.fixtures; let at = &ts.fixtures;
@ -217,8 +224,9 @@ fn test_permission_denied() {
.code_is(1); .code_is(1);
} }
// TODO: Add similar test for windows
#[test] #[test]
#[cfg(all(unix, not(target_os = "freebsd")))] #[cfg(unix)]
fn test_permission_denied_multiple() { fn test_permission_denied_multiple() {
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
let at = &ts.fixtures; let at = &ts.fixtures;
@ -241,7 +249,6 @@ fn test_permission_denied_multiple() {
} }
#[test] #[test]
#[cfg(target_os = "linux")]
fn test_follow_redirect_stdin_name_retry() { fn test_follow_redirect_stdin_name_retry() {
// $ touch f && tail -F - < f // $ touch f && tail -F - < f
// tail: cannot follow '-' by name // tail: cannot follow '-' by name
@ -265,8 +272,12 @@ fn test_follow_redirect_stdin_name_retry() {
} }
#[test] #[test]
#[cfg(not(target_os = "macos"))] // See test_stdin_redirect_dir_when_target_os_is_macos #[cfg(all(
#[cfg(all(unix, not(any(target_os = "android", target_os = "freebsd"))))] // FIXME: fix this test for Android/FreeBSD not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_stdin_redirect_dir() { fn test_stdin_redirect_dir() {
// $ mkdir dir // $ mkdir dir
// $ tail < dir, $ tail - < dir // $ tail < dir, $ tail - < dir
@ -299,7 +310,7 @@ fn test_stdin_redirect_dir() {
// redirected directories like linux show the correct message like in // redirected directories like linux show the correct message like in
// `test_stdin_redirect_dir` // `test_stdin_redirect_dir`
#[test] #[test]
#[cfg(target_os = "macos")] #[cfg(target_vendor = "apple")]
fn test_stdin_redirect_dir_when_target_os_is_macos() { fn test_stdin_redirect_dir_when_target_os_is_macos() {
// $ mkdir dir // $ mkdir dir
// $ tail < dir, $ tail - < dir // $ tail < dir, $ tail - < dir
@ -325,7 +336,6 @@ fn test_stdin_redirect_dir_when_target_os_is_macos() {
} }
#[test] #[test]
#[cfg(target_os = "linux")]
fn test_follow_stdin_descriptor() { fn test_follow_stdin_descriptor() {
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
@ -345,7 +355,6 @@ fn test_follow_stdin_descriptor() {
} }
#[test] #[test]
#[cfg(target_os = "linux")]
fn test_follow_stdin_name_retry() { fn test_follow_stdin_name_retry() {
// $ tail -F - // $ tail -F -
// tail: cannot follow '-' by name // tail: cannot follow '-' by name
@ -417,8 +426,6 @@ fn test_follow_stdin_explicit_indefinitely() {
} }
#[test] #[test]
#[cfg(target_os = "linux")]
#[cfg(disable_until_fixed)]
fn test_follow_bad_fd() { fn test_follow_bad_fd() {
// Provoke a "bad file descriptor" error by closing the fd // Provoke a "bad file descriptor" error by closing the fd
// inspired by: "gnu/tests/tail-2/follow-stdin.sh" // inspired by: "gnu/tests/tail-2/follow-stdin.sh"
@ -465,7 +472,7 @@ fn test_null_default() {
} }
#[test] #[test]
#[cfg(unix)] #[cfg(not(target_os = "windows"))] // FIXME: test times out
fn test_follow_single() { fn test_follow_single() {
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
@ -489,7 +496,7 @@ fn test_follow_single() {
/// Test for following when bytes are written that are not valid UTF-8. /// Test for following when bytes are written that are not valid UTF-8.
#[test] #[test]
#[cfg(unix)] #[cfg(not(target_os = "windows"))] // FIXME: test times out
fn test_follow_non_utf8_bytes() { fn test_follow_non_utf8_bytes() {
// Tail the test file and start following it. // Tail the test file and start following it.
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
@ -521,7 +528,7 @@ fn test_follow_non_utf8_bytes() {
} }
#[test] #[test]
#[cfg(unix)] #[cfg(not(target_os = "windows"))] // FIXME: test times out
fn test_follow_multiple() { fn test_follow_multiple() {
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
let mut child = ucmd let mut child = ucmd
@ -547,7 +554,7 @@ fn test_follow_multiple() {
} }
#[test] #[test]
#[cfg(unix)] #[cfg(not(target_os = "windows"))] // FIXME: test times out
fn test_follow_name_multiple() { fn test_follow_name_multiple() {
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
let mut child = ucmd let mut child = ucmd
@ -573,7 +580,6 @@ fn test_follow_name_multiple() {
} }
#[test] #[test]
#[cfg(unix)]
fn test_follow_multiple_untailable() { fn test_follow_multiple_untailable() {
// $ tail -f DIR1 DIR2 // $ tail -f DIR1 DIR2
// ==> DIR1 <== // ==> DIR1 <==
@ -606,7 +612,6 @@ fn test_follow_multiple_untailable() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_follow_stdin_pipe() { fn test_follow_stdin_pipe() {
new_ucmd!() new_ucmd!()
.arg("-f") .arg("-f")
@ -617,7 +622,7 @@ fn test_follow_stdin_pipe() {
} }
#[test] #[test]
#[cfg(unix)] #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms
fn test_follow_invalid_pid() { fn test_follow_invalid_pid() {
new_ucmd!() new_ucmd!()
.args(&["-f", "--pid=-1234"]) .args(&["-f", "--pid=-1234"])
@ -641,8 +646,12 @@ fn test_follow_invalid_pid() {
} }
// FixME: test PASSES for usual windows builds, but fails for coverage testing builds (likely related to the specific RUSTFLAGS '-Zpanic_abort_tests -Cpanic=abort') This test also breaks tty settings under bash requiring a 'stty sane' or reset. // spell-checker:disable-line // FixME: test PASSES for usual windows builds, but fails for coverage testing builds (likely related to the specific RUSTFLAGS '-Zpanic_abort_tests -Cpanic=abort') This test also breaks tty settings under bash requiring a 'stty sane' or reset. // spell-checker:disable-line
#[cfg(disable_until_fixed)]
#[test] #[test]
#[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android")
))] // FIXME: for currently not working platforms
fn test_follow_with_pid() { fn test_follow_with_pid() {
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::thread::sleep; use std::thread::sleep;
@ -652,6 +661,7 @@ fn test_follow_with_pid() {
#[cfg(unix)] #[cfg(unix)]
let dummy_cmd = "sh"; let dummy_cmd = "sh";
#[cfg(windows)] #[cfg(windows)]
let dummy_cmd = "cmd"; let dummy_cmd = "cmd";
@ -687,13 +697,18 @@ fn test_follow_with_pid() {
let third_append = "should\nbe\nignored\n"; let third_append = "should\nbe\nignored\n";
at.append(FOOBAR_TXT, third_append); at.append(FOOBAR_TXT, third_append);
assert_eq!(read_size(&mut child, 1), "\u{0}"); let mut buffer: [u8; 1] = [0; 1];
let result = child.stdout.as_mut().unwrap().read(&mut buffer);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0);
// On Unix, trying to kill a process that's already dead is fine; on Windows it's an error. // On Unix, trying to kill a process that's already dead is fine; on Windows it's an error.
#[cfg(unix)] let result = child.kill();
child.kill().unwrap(); if cfg!(windows) {
#[cfg(windows)] assert!(result.is_err());
assert_eq!(child.kill().is_err(), true); } else {
assert!(result.is_ok());
}
} }
#[test] #[test]
@ -735,7 +750,6 @@ fn test_bytes_single() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_bytes_stdin() { fn test_bytes_stdin() {
new_ucmd!() new_ucmd!()
.pipe_in_fixture(FOOBAR_TXT) .pipe_in_fixture(FOOBAR_TXT)
@ -984,7 +998,6 @@ fn test_sleep_interval() {
/// Test for reading all but the first NUM bytes: `tail -c +3`. /// Test for reading all but the first NUM bytes: `tail -c +3`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_positive_bytes() { fn test_positive_bytes() {
new_ucmd!() new_ucmd!()
.args(&["-c", "+3"]) .args(&["-c", "+3"])
@ -995,7 +1008,6 @@ fn test_positive_bytes() {
/// Test for reading all bytes, specified by `tail -c +0`. /// Test for reading all bytes, specified by `tail -c +0`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_positive_zero_bytes() { fn test_positive_zero_bytes() {
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
ts.ucmd() ts.ucmd()
@ -1013,7 +1025,6 @@ fn test_positive_zero_bytes() {
/// Test for reading all but the first NUM lines: `tail -n +3`. /// Test for reading all but the first NUM lines: `tail -n +3`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_positive_lines() { fn test_positive_lines() {
new_ucmd!() new_ucmd!()
.args(&["-n", "+3"]) .args(&["-n", "+3"])
@ -1055,7 +1066,6 @@ once
/// Test for reading all but the first NUM lines: `tail -3`. /// Test for reading all but the first NUM lines: `tail -3`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_obsolete_syntax_positive_lines() { fn test_obsolete_syntax_positive_lines() {
new_ucmd!() new_ucmd!()
.args(&["-3"]) .args(&["-3"])
@ -1066,7 +1076,6 @@ fn test_obsolete_syntax_positive_lines() {
/// Test for reading all but the first NUM lines: `tail -n -10`. /// Test for reading all but the first NUM lines: `tail -n -10`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_small_file() { fn test_small_file() {
new_ucmd!() new_ucmd!()
.args(&["-n -10"]) .args(&["-n -10"])
@ -1077,7 +1086,6 @@ fn test_small_file() {
/// Test for reading all but the first NUM lines: `tail -10`. /// Test for reading all but the first NUM lines: `tail -10`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_obsolete_syntax_small_file() { fn test_obsolete_syntax_small_file() {
new_ucmd!() new_ucmd!()
.args(&["-10"]) .args(&["-10"])
@ -1088,7 +1096,6 @@ fn test_obsolete_syntax_small_file() {
/// Test for reading all lines, specified by `tail -n +0`. /// Test for reading all lines, specified by `tail -n +0`.
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_positive_zero_lines() { fn test_positive_zero_lines() {
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
ts.ucmd() ts.ucmd()
@ -1106,7 +1113,6 @@ fn test_positive_zero_lines() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_invalid_num() { fn test_invalid_num() {
new_ucmd!() new_ucmd!()
.args(&["-c", "1024R", "emptyfile.txt"]) .args(&["-c", "1024R", "emptyfile.txt"])
@ -1138,7 +1144,6 @@ fn test_invalid_num() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_num_with_undocumented_sign_bytes() { fn test_num_with_undocumented_sign_bytes() {
// tail: '-' is not documented (8.32 man pages) // tail: '-' is not documented (8.32 man pages)
// head: '+' is not documented (8.32 man pages) // head: '+' is not documented (8.32 man pages)
@ -1162,7 +1167,7 @@ fn test_num_with_undocumented_sign_bytes() {
#[test] #[test]
#[cfg(unix)] #[cfg(unix)]
fn test_bytes_for_funny_files() { fn test_bytes_for_funny_unix_files() {
// inspired by: gnu/tests/tail-2/tail-c.sh // inspired by: gnu/tests/tail-2/tail-c.sh
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
let at = &ts.fixtures; let at = &ts.fixtures;
@ -1181,7 +1186,6 @@ fn test_bytes_for_funny_files() {
} }
#[test] #[test]
#[cfg(unix)]
fn test_retry1() { fn test_retry1() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// Ensure --retry without --follow results in a warning. // Ensure --retry without --follow results in a warning.
@ -1198,7 +1202,6 @@ fn test_retry1() {
} }
#[test] #[test]
#[cfg(unix)]
fn test_retry2() { fn test_retry2() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// The same as test_retry2 with a missing file: expect error message and exit 1. // The same as test_retry2 with a missing file: expect error message and exit 1.
@ -1221,7 +1224,12 @@ fn test_retry2() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_retry3() { fn test_retry3() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// Ensure that `tail --retry --follow=name` waits for the file to appear. // Ensure that `tail --retry --follow=name` waits for the file to appear.
@ -1259,7 +1267,12 @@ fn test_retry3() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_retry4() { fn test_retry4() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// Ensure that `tail --retry --follow=descriptor` waits for the file to appear. // Ensure that `tail --retry --follow=descriptor` waits for the file to appear.
@ -1309,7 +1322,12 @@ fn test_retry4() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_retry5() { fn test_retry5() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// Ensure that `tail --follow=descriptor --retry` exits when the file appears untailable. // Ensure that `tail --follow=descriptor --retry` exits when the file appears untailable.
@ -1345,7 +1363,7 @@ fn test_retry5() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms
fn test_retry6() { fn test_retry6() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// Ensure that --follow=descriptor (without --retry) does *not* try // Ensure that --follow=descriptor (without --retry) does *not* try
@ -1383,7 +1401,12 @@ fn test_retry6() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_retry7() { fn test_retry7() {
// inspired by: gnu/tests/tail-2/retry.sh // inspired by: gnu/tests/tail-2/retry.sh
// Ensure that `tail -F` retries when the file is initially untailable. // Ensure that `tail -F` retries when the file is initially untailable.
@ -1450,7 +1473,12 @@ fn test_retry7() {
} }
#[test] #[test]
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_retry8() { fn test_retry8() {
// Ensure that inotify will switch to polling mode if directory // Ensure that inotify will switch to polling mode if directory
// of the watched file was initially missing and later created. // of the watched file was initially missing and later created.
@ -1512,7 +1540,11 @@ fn test_retry8() {
} }
#[test] #[test]
#[cfg(all(unix, not(any(target_os = "android", target_vendor = "apple"))))] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_retry9() { fn test_retry9() {
// inspired by: gnu/tests/tail-2/inotify-dir-recreate.sh // inspired by: gnu/tests/tail-2/inotify-dir-recreate.sh
// Ensure that inotify will switch to polling mode if directory // Ensure that inotify will switch to polling mode if directory
@ -1589,7 +1621,11 @@ fn test_retry9() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_descriptor_vs_rename1() { fn test_follow_descriptor_vs_rename1() {
// inspired by: gnu/tests/tail-2/descriptor-vs-rename.sh // inspired by: gnu/tests/tail-2/descriptor-vs-rename.sh
// $ ((rm -f A && touch A && sleep 1 && echo -n "A\n" >> A && sleep 1 && \ // $ ((rm -f A && touch A && sleep 1 && echo -n "A\n" >> A && sleep 1 && \
@ -1646,7 +1682,11 @@ fn test_follow_descriptor_vs_rename1() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_descriptor_vs_rename2() { fn test_follow_descriptor_vs_rename2() {
// Ensure the headers are correct for --verbose. // Ensure the headers are correct for --verbose.
// NOTE: GNU's tail does not update the header from FILE_A to FILE_C after `mv FILE_A FILE_C` // NOTE: GNU's tail does not update the header from FILE_A to FILE_C after `mv FILE_A FILE_C`
@ -1695,7 +1735,12 @@ fn test_follow_descriptor_vs_rename2() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_retry_headers() { fn test_follow_name_retry_headers() {
// inspired by: "gnu/tests/tail-2/F-headers.sh" // inspired by: "gnu/tests/tail-2/F-headers.sh"
// Ensure tail -F distinguishes output with the // Ensure tail -F distinguishes output with the
@ -1756,7 +1801,7 @@ fn test_follow_name_retry_headers() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: make this work not just on Linux #[cfg(all(not(target_os = "windows"), not(target_os = "android")))] // FIXME: for currently not working platforms
fn test_follow_name_remove() { fn test_follow_name_remove() {
// This test triggers a remove event while `tail --follow=name file` is running. // This test triggers a remove event while `tail --follow=name file` is running.
// ((sleep 2 && rm file &)>/dev/null 2>&1 &) ; tail --follow=name file // ((sleep 2 && rm file &)>/dev/null 2>&1 &) ; tail --follow=name file
@ -1805,7 +1850,11 @@ fn test_follow_name_remove() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_truncate1() { fn test_follow_name_truncate1() {
// This test triggers a truncate event while `tail --follow=name file` is running. // This test triggers a truncate event while `tail --follow=name file` is running.
// $ cp file backup && head file > file && sleep 1 && cp backup file // $ cp file backup && head file > file && sleep 1 && cp backup file
@ -1839,7 +1888,11 @@ fn test_follow_name_truncate1() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(all(
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_truncate2() { fn test_follow_name_truncate2() {
// This test triggers a truncate event while `tail --follow=name file` is running. // This test triggers a truncate event while `tail --follow=name file` is running.
// $ ((sleep 1 && echo -n "x\nx\nx\n" >> file && sleep 1 && \ // $ ((sleep 1 && echo -n "x\nx\nx\n" >> file && sleep 1 && \
@ -1876,7 +1929,7 @@ fn test_follow_name_truncate2() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: fix this test for BSD/macOS #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms
fn test_follow_name_truncate3() { fn test_follow_name_truncate3() {
// Opening an empty file in truncate mode should not trigger a truncate event while // Opening an empty file in truncate mode should not trigger a truncate event while
// `tail --follow=name file` is running. // `tail --follow=name file` is running.
@ -1907,7 +1960,7 @@ fn test_follow_name_truncate3() {
} }
#[test] #[test]
#[cfg(unix)] #[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] // FIXME: for currently not working platforms
fn test_follow_name_truncate4() { fn test_follow_name_truncate4() {
// Truncating a file with the same content it already has should not trigger a truncate event // Truncating a file with the same content it already has should not trigger a truncate event
@ -1939,7 +1992,7 @@ fn test_follow_name_truncate4() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms
fn test_follow_truncate_fast() { fn test_follow_truncate_fast() {
// inspired by: "gnu/tests/tail-2/truncate.sh" // inspired by: "gnu/tests/tail-2/truncate.sh"
// Ensure all logs are output upon file truncation // Ensure all logs are output upon file truncation
@ -1989,7 +2042,12 @@ fn test_follow_truncate_fast() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_move_create1() { fn test_follow_name_move_create1() {
// This test triggers a move/create event while `tail --follow=name file` is running. // This test triggers a move/create event while `tail --follow=name file` is running.
// ((sleep 2 && mv file backup && sleep 2 && cp backup file &)>/dev/null 2>&1 &) ; tail --follow=name file // ((sleep 2 && mv file backup && sleep 2 && cp backup file &)>/dev/null 2>&1 &) ; tail --follow=name file
@ -2002,6 +2060,7 @@ fn test_follow_name_move_create1() {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
let expected_stdout = at.read(FOLLOW_NAME_EXP); let expected_stdout = at.read(FOLLOW_NAME_EXP);
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
let expected_stderr = format!( let expected_stderr = format!(
"{}: {}: No such file or directory\n{0}: '{1}' has appeared; following new file\n", "{}: {}: No such file or directory\n{0}: '{1}' has appeared; following new file\n",
@ -2009,8 +2068,10 @@ fn test_follow_name_move_create1() {
); );
// NOTE: We are less strict if not on Linux (inotify backend). // NOTE: We are less strict if not on Linux (inotify backend).
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
let expected_stdout = at.read(FOLLOW_NAME_SHORT_EXP); let expected_stdout = at.read(FOLLOW_NAME_SHORT_EXP);
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
let expected_stderr = format!("{}: {}: No such file or directory\n", ts.util_name, source); let expected_stderr = format!("{}: {}: No such file or directory\n", ts.util_name, source);
@ -2034,7 +2095,11 @@ fn test_follow_name_move_create1() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_move_create2() { fn test_follow_name_move_create2() {
// inspired by: "gnu/tests/tail-2/inotify-hash-abuse.sh" // inspired by: "gnu/tests/tail-2/inotify-hash-abuse.sh"
// Exercise an abort-inducing flaw in inotify-enabled tail -F // Exercise an abort-inducing flaw in inotify-enabled tail -F
@ -2105,7 +2170,12 @@ fn test_follow_name_move_create2() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_move1() { fn test_follow_name_move1() {
// This test triggers a move event while `tail --follow=name file` is running. // This test triggers a move event while `tail --follow=name file` is running.
// ((sleep 2 && mv file backup &)>/dev/null 2>&1 &) ; tail --follow=name file // ((sleep 2 && mv file backup &)>/dev/null 2>&1 &) ; tail --follow=name file
@ -2150,7 +2220,12 @@ fn test_follow_name_move1() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_move2() { fn test_follow_name_move2() {
// Like test_follow_name_move1, but move to a name that's already monitored. // Like test_follow_name_move1, but move to a name that's already monitored.
@ -2231,7 +2306,12 @@ fn test_follow_name_move2() {
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_move_retry1() { fn test_follow_name_move_retry1() {
// Similar to test_follow_name_move1 but with `--retry` (`-F`) // Similar to test_follow_name_move1 but with `--retry` (`-F`)
// This test triggers two move/rename events while `tail --follow=name --retry file` is running. // This test triggers two move/rename events while `tail --follow=name --retry file` is running.
@ -2281,8 +2361,14 @@ fn test_follow_name_move_retry1() {
delay /= 3; delay /= 3;
} }
} }
#[test] #[test]
#[cfg(target_os = "linux")] // FIXME: make this work not just on Linux #[cfg(all(
not(target_vendor = "apple"),
not(target_os = "windows"),
not(target_os = "android"),
not(target_os = "freebsd")
))] // FIXME: for currently not working platforms
fn test_follow_name_move_retry2() { fn test_follow_name_move_retry2() {
// inspired by: "gnu/tests/tail-2/F-vs-rename.sh" // inspired by: "gnu/tests/tail-2/F-vs-rename.sh"
// Similar to test_follow_name_move2 (move to a name that's already monitored) // Similar to test_follow_name_move2 (move to a name that's already monitored)
@ -2380,7 +2466,7 @@ fn test_follow_name_move_retry2() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "freebsd")))] // FIXME: fix this test for FreeBSD #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms
fn test_follow_inotify_only_regular() { fn test_follow_inotify_only_regular() {
// The GNU test inotify-only-regular.sh uses strace to ensure that `tail -f` // The GNU test inotify-only-regular.sh uses strace to ensure that `tail -f`
// doesn't make inotify syscalls and only uses inotify for regular files or fifos. // doesn't make inotify syscalls and only uses inotify for regular files or fifos.
@ -2403,7 +2489,6 @@ fn test_follow_inotify_only_regular() {
assert_eq!(buf_stderr, "".to_string()); assert_eq!(buf_stderr, "".to_string());
} }
#[cfg(unix)]
fn take_stdout_stderr(p: &mut std::process::Child) -> (String, String) { fn take_stdout_stderr(p: &mut std::process::Child) -> (String, String) {
let mut buf_stdout = String::new(); let mut buf_stdout = String::new();
let mut p_stdout = p.stdout.take().unwrap(); let mut p_stdout = p.stdout.take().unwrap();
@ -2426,13 +2511,11 @@ fn test_no_such_file() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_no_trailing_newline() { fn test_no_trailing_newline() {
new_ucmd!().pipe_in("x").succeeds().stdout_only("x"); new_ucmd!().pipe_in("x").succeeds().stdout_only("x");
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_lines_zero_terminated() { fn test_lines_zero_terminated() {
new_ucmd!() new_ucmd!()
.args(&["-z", "-n", "2"]) .args(&["-z", "-n", "2"])
@ -2447,7 +2530,6 @@ fn test_lines_zero_terminated() {
} }
#[test] #[test]
#[cfg(all(unix, not(target_os = "android")))] // FIXME: fix this test for Android
fn test_presume_input_pipe_default() { fn test_presume_input_pipe_default() {
new_ucmd!() new_ucmd!()
.arg("---presume-input-pipe") .arg("---presume-input-pipe")
@ -2458,7 +2540,7 @@ fn test_presume_input_pipe_default() {
} }
#[test] #[test]
#[cfg(unix)] #[cfg(not(windows))]
fn test_fifo() { fn test_fifo() {
let ts = TestScenario::new(util_name!()); let ts = TestScenario::new(util_name!());
let at = &ts.fixtures; let at = &ts.fixtures;
@ -2512,14 +2594,8 @@ fn test_illegal_seek() {
assert_eq!(p.wait().unwrap().code().unwrap(), 1); assert_eq!(p.wait().unwrap().code().unwrap(), 1);
} }
#[cfg(all(not(target_os = "android"), not(target_os = "windows")))] // FIXME: See https://github.com/uutils/coreutils/issues/3881 #[test]
mod pipe_tests { fn test_pipe_when_lines_option_value_is_higher_than_contained_lines() {
use super::*;
use rand::distributions::Alphanumeric;
use tail::chunks::BUFFER_SIZE as CHUNK_BUFFER_SIZE;
#[test]
fn test_pipe_when_lines_option_value_is_higher_than_contained_lines() {
let test_string = "a\nb\n"; let test_string = "a\nb\n";
new_ucmd!() new_ucmd!()
.args(&["-n", "3"]) .args(&["-n", "3"])
@ -2565,10 +2641,10 @@ mod pipe_tests {
.succeeds() .succeeds()
.no_stdout() .no_stdout()
.no_stderr(); .no_stderr();
} }
#[test] #[test]
fn test_pipe_when_negative_lines_option_given_no_newline_at_eof() { fn test_pipe_when_negative_lines_option_given_no_newline_at_eof() {
let test_string = "a\nb"; let test_string = "a\nb";
new_ucmd!() new_ucmd!()
@ -2592,10 +2668,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only("a\nb"); .stdout_only("a\nb");
} }
#[test] #[test]
fn test_pipe_when_positive_lines_option_given_no_newline_at_eof() { fn test_pipe_when_positive_lines_option_given_no_newline_at_eof() {
let test_string = "a\nb"; let test_string = "a\nb";
new_ucmd!() new_ucmd!()
@ -2618,10 +2694,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only("b"); .stdout_only("b");
} }
#[test] #[test]
fn test_pipe_when_lines_option_given_multibyte_utf8_characters() { fn test_pipe_when_lines_option_given_multibyte_utf8_characters() {
// the test string consists of from left to right a 4-byte,3-byte,2-byte,1-byte utf-8 character // the test string consists of from left to right a 4-byte,3-byte,2-byte,1-byte utf-8 character
let test_string = "𝅘𝅥𝅮\n\nƒ\na"; let test_string = "𝅘𝅥𝅮\n\nƒ\na";
@ -2696,10 +2772,10 @@ mod pipe_tests {
.succeeds() .succeeds()
.no_stdout() .no_stdout()
.no_stderr(); .no_stderr();
} }
#[test] #[test]
fn test_pipe_when_lines_option_given_input_size_is_equal_to_buffer_size_no_newline_at_eof() { fn test_pipe_when_lines_option_given_input_size_is_equal_to_buffer_size_no_newline_at_eof() {
let total_lines = 1; let total_lines = 1;
let random_string = RandomString::generate_with_delimiter( let random_string = RandomString::generate_with_delimiter(
Alphanumeric, Alphanumeric,
@ -2726,10 +2802,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(expected); .stdout_only(expected);
} }
#[test] #[test]
fn test_pipe_when_lines_option_given_input_size_is_equal_to_buffer_size() { fn test_pipe_when_lines_option_given_input_size_is_equal_to_buffer_size() {
let total_lines = 100; let total_lines = 100;
let random_string = RandomString::generate_with_delimiter( let random_string = RandomString::generate_with_delimiter(
Alphanumeric, Alphanumeric,
@ -2786,10 +2862,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(random_string); .stdout_only(random_string);
} }
#[test] #[test]
fn test_pipe_when_lines_option_given_input_size_is_one_byte_greater_than_buffer_size() { fn test_pipe_when_lines_option_given_input_size_is_one_byte_greater_than_buffer_size() {
let total_lines = 100; let total_lines = 100;
let random_string = RandomString::generate_with_delimiter( let random_string = RandomString::generate_with_delimiter(
Alphanumeric, Alphanumeric,
@ -2831,10 +2907,13 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(expected); .stdout_only(expected);
} }
#[test] // FIXME: windows: this test failed with timeout in the CI. Running this test in
fn test_pipe_when_lines_option_given_input_size_has_multiple_size_of_buffer_size() { // a Windows VirtualBox image produces no errors.
#[test]
#[cfg(not(target_os = "windows"))]
fn test_pipe_when_lines_option_given_input_size_has_multiple_size_of_buffer_size() {
let total_lines = 100; let total_lines = 100;
let random_string = RandomString::generate_with_delimiter( let random_string = RandomString::generate_with_delimiter(
Alphanumeric, Alphanumeric,
@ -2891,10 +2970,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(random_string); .stdout_only(random_string);
} }
#[test] #[test]
fn test_pipe_when_bytes_option_value_is_higher_than_contained_bytes() { fn test_pipe_when_bytes_option_value_is_higher_than_contained_bytes() {
let test_string = "a\nb"; let test_string = "a\nb";
new_ucmd!() new_ucmd!()
.args(&["-c", "4"]) .args(&["-c", "4"])
@ -2940,10 +3019,10 @@ mod pipe_tests {
.succeeds() .succeeds()
.no_stdout() .no_stdout()
.no_stderr(); .no_stderr();
} }
#[test] #[test]
fn test_pipe_when_bytes_option_given_multibyte_utf8_characters() { fn test_pipe_when_bytes_option_given_multibyte_utf8_characters() {
// the test string consists of from left to right a 4-byte,3-byte,2-byte,1-byte utf-8 character // the test string consists of from left to right a 4-byte,3-byte,2-byte,1-byte utf-8 character
let test_string = "𝅘𝅥𝅮⏻ƒa"; let test_string = "𝅘𝅥𝅮⏻ƒa";
@ -3024,10 +3103,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(test_string); .stdout_only(test_string);
} }
#[test] #[test]
fn test_pipe_when_bytes_option_given_input_size_is_equal_to_buffer_size() { fn test_pipe_when_bytes_option_given_input_size_is_equal_to_buffer_size() {
let random_string = RandomString::generate(AlphanumericNewline, CHUNK_BUFFER_SIZE); let random_string = RandomString::generate(AlphanumericNewline, CHUNK_BUFFER_SIZE);
let random_string = random_string.as_str(); let random_string = random_string.as_str();
@ -3083,10 +3162,10 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only_bytes(expected); .stdout_only_bytes(expected);
} }
#[test] #[test]
fn test_pipe_when_bytes_option_given_input_size_is_one_byte_greater_than_buffer_size() { fn test_pipe_when_bytes_option_given_input_size_is_one_byte_greater_than_buffer_size() {
let random_string = RandomString::generate(AlphanumericNewline, CHUNK_BUFFER_SIZE + 1); let random_string = RandomString::generate(AlphanumericNewline, CHUNK_BUFFER_SIZE + 1);
let random_string = random_string.as_str(); let random_string = random_string.as_str();
@ -3135,10 +3214,13 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(random_string); .stdout_only(random_string);
} }
#[test] // FIXME: windows: this test failed with timeout in the CI. Running this test in
fn test_pipe_when_bytes_option_given_input_size_has_multiple_size_of_buffer_size() { // a Windows VirtualBox image produces no errors.
#[test]
#[cfg(not(target_os = "windows"))]
fn test_pipe_when_bytes_option_given_input_size_has_multiple_size_of_buffer_size() {
let random_string = RandomString::generate(AlphanumericNewline, CHUNK_BUFFER_SIZE * 3); let random_string = RandomString::generate(AlphanumericNewline, CHUNK_BUFFER_SIZE * 3);
let random_string = random_string.as_str(); let random_string = random_string.as_str();
@ -3227,7 +3309,6 @@ mod pipe_tests {
.ignore_stdin_write_error() .ignore_stdin_write_error()
.succeeds() .succeeds()
.stdout_only(random_string); .stdout_only(random_string);
}
} }
#[test] #[test]

View file

@ -311,4 +311,30 @@ mod tests {
); );
assert!(random_string.as_bytes().ends_with(&[0])); assert!(random_string.as_bytes().ends_with(&[0]));
} }
/// Originally used to exclude an error within the `random` module. The two
/// affected tests timed out on windows, but only in the ci. These tests are
/// also the source for the concrete numbers. The timed out tests are
/// `test_tail.rs::test_pipe_when_lines_option_given_input_size_has_multiple_size_of_buffer_size`
/// `test_tail.rs::test_pipe_when_bytes_option_given_input_size_has_multiple_size_of_buffer_size`.
#[test]
fn test_generate_random_strings_when_length_is_around_critical_buffer_sizes() {
let length = 8192 * 3;
let random_string = RandomString::generate(AlphanumericNewline, length);
assert_eq!(length, random_string.len());
let length = 8192 * 3 + 1;
let random_string =
RandomString::generate_with_delimiter(&Alphanumeric, b'\n', 100, true, length);
assert_eq!(length, random_string.len());
assert_eq!(
100,
random_string
.as_bytes()
.iter()
.filter(|p| **p == b'\n')
.count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
}
} }