coreutils/tests/by-util/test_sleep.rs
2024-10-25 16:47:40 +02:00

274 lines
7.1 KiB
Rust

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use rstest::rstest;
// spell-checker:ignore dont SIGBUS SIGSEGV sigsegv sigbus
use crate::common::util::TestScenario;
#[cfg(unix)]
use nix::sys::signal::Signal::{SIGBUS, SIGSEGV};
use std::time::{Duration, Instant};
#[test]
fn test_invalid_time_interval() {
new_ucmd!()
.arg("xyz")
.fails()
.usage_error("invalid time interval 'xyz': Invalid input: xyz");
new_ucmd!()
.args(&["--", "-1"])
.fails()
.usage_error("invalid time interval '-1': Number was negative");
}
#[test]
fn test_sleep_no_suffix() {
let millis_100 = Duration::from_millis(100);
let before_test = Instant::now();
new_ucmd!().args(&["0.1"]).succeeds().stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_100);
}
#[test]
fn test_sleep_s_suffix() {
let millis_100 = Duration::from_millis(100);
let before_test = Instant::now();
new_ucmd!().args(&["0.1s"]).succeeds().stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_100);
}
#[test]
fn test_sleep_m_suffix() {
let millis_600 = Duration::from_millis(600);
let before_test = Instant::now();
new_ucmd!().args(&["0.01m"]).succeeds().stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_600);
}
#[test]
fn test_sleep_h_suffix() {
let millis_360 = Duration::from_millis(360);
let before_test = Instant::now();
new_ucmd!().args(&["0.0001h"]).succeeds().stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_360);
}
#[test]
fn test_sleep_negative_duration() {
new_ucmd!().args(&["-1"]).fails();
new_ucmd!().args(&["-1s"]).fails();
new_ucmd!().args(&["-1m"]).fails();
new_ucmd!().args(&["-1h"]).fails();
new_ucmd!().args(&["-1d"]).fails();
}
#[test]
fn test_sleep_zero_duration() {
new_ucmd!().args(&["0"]).succeeds().stdout_only("");
new_ucmd!().args(&["0s"]).succeeds().stdout_only("");
new_ucmd!().args(&["0m"]).succeeds().stdout_only("");
new_ucmd!().args(&["0h"]).succeeds().stdout_only("");
new_ucmd!().args(&["0d"]).succeeds().stdout_only("");
}
#[test]
fn test_sleep_no_argument() {
new_ucmd!().fails().usage_error("missing operand");
}
#[test]
fn test_sleep_sum_duration_same_suffix() {
let millis_200 = Duration::from_millis(100 + 100);
let before_test = Instant::now();
new_ucmd!()
.args(&["0.1s", "0.1s"])
.succeeds()
.stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_200);
}
#[test]
fn test_sleep_sum_duration_different_suffix() {
let millis_700 = Duration::from_millis(100 + 600);
let before_test = Instant::now();
new_ucmd!()
.args(&["0.1s", "0.01m"])
.succeeds()
.stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_700);
}
#[test]
fn test_sleep_sum_duration_many() {
let millis_900 = Duration::from_millis(100 + 100 + 300 + 400);
let before_test = Instant::now();
new_ucmd!()
.args(&["0.1s", "0.1s", "0.3s", "0.4s"])
.succeeds()
.stdout_only("");
let duration = before_test.elapsed();
assert!(duration >= millis_900);
}
#[test]
fn test_sleep_wrong_time() {
new_ucmd!().args(&["0.1s", "abc"]).fails();
}
#[test]
#[cfg(unix)]
fn test_sleep_stops_after_sigsegv() {
let mut child = new_ucmd!()
.arg("100")
.timeout(Duration::from_secs(10))
.run_no_wait();
child
.delay(100)
.kill_with_custom_signal(SIGSEGV)
.make_assertion()
.with_current_output()
.signal_is(SIGSEGV as i32) // make sure it was us who terminated the process
.no_output();
}
#[test]
#[cfg(unix)]
fn test_sleep_stops_after_sigbus() {
let mut child = new_ucmd!()
.arg("100")
.timeout(Duration::from_secs(10))
.run_no_wait();
child
.delay(100)
.kill_with_custom_signal(SIGBUS)
.make_assertion()
.with_current_output()
.signal_is(SIGBUS as i32) // make sure it was us who terminated the process
.no_output();
}
#[test]
fn test_sleep_when_single_input_exceeds_max_duration_then_no_error() {
let mut child = new_ucmd!()
.arg(format!("{}", u128::from(u64::MAX) + 1))
.timeout(Duration::from_secs(10))
.run_no_wait();
#[cfg(unix)]
child
.delay(100)
.kill()
.make_assertion()
.with_current_output()
.signal_is(9) // make sure it was us who terminated the process
.no_output();
#[cfg(windows)]
child
.delay(100)
.kill()
.make_assertion()
.with_current_output()
.failure()
.no_output();
}
#[test]
fn test_sleep_when_multiple_inputs_exceed_max_duration_then_no_error() {
let mut child = new_ucmd!()
.arg(format!("{}", u64::MAX))
.arg("1")
.timeout(Duration::from_secs(10))
.run_no_wait();
#[cfg(unix)]
child
.delay(100)
.kill()
.make_assertion()
.with_current_output()
.signal_is(9) // make sure it was us who terminated the process
.no_output();
#[cfg(windows)]
child
.delay(100)
.kill()
.make_assertion()
.with_current_output()
.failure()
.no_output();
}
#[rstest]
#[case::whitespace_prefix(" 0.1s")]
#[case::multiple_whitespace_prefix(" 0.1s")]
#[case::whitespace_suffix("0.1s ")]
#[case::mixed_newlines_spaces_tabs("\n\t0.1s \n ")]
fn test_sleep_when_input_has_whitespace_then_no_error(#[case] input: &str) {
new_ucmd!()
.arg(input)
.timeout(Duration::from_secs(10))
.succeeds()
.no_output();
}
#[rstest]
#[case::only_space(" ")]
#[case::only_tab("\t")]
#[case::only_newline("\n")]
fn test_sleep_when_input_has_only_whitespace_then_error(#[case] input: &str) {
new_ucmd!()
.arg(input)
.timeout(Duration::from_secs(10))
.fails()
.usage_error(format!(
"invalid time interval '{input}': Found only whitespace in input"
));
}
#[test]
fn test_sleep_when_multiple_input_some_with_error_then_shows_all_errors() {
let expected = "invalid time interval 'abc': Invalid input: abc\n\
sleep: invalid time interval '1years': Invalid time unit: 'years' at position 2\n\
sleep: invalid time interval ' ': Found only whitespace in input";
// Even if one of the arguments is valid, but the rest isn't, we should still fail and exit early.
// So, the timeout of 10 seconds ensures we haven't executed `thread::sleep` with the only valid
// interval of `100000.0` seconds.
new_ucmd!()
.args(&["abc", "100000.0", "1years", " "])
.timeout(Duration::from_secs(10))
.fails()
.usage_error(expected);
}
#[test]
fn test_negative_interval() {
new_ucmd!()
.args(&["--", "-1"])
.fails()
.usage_error("invalid time interval '-1': Number was negative");
}