diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index 59d3c6c64..66f4f1309 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -18,11 +18,7 @@ fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String { i.modified() .map(|x| { let date_time: OffsetDateTime = x.into(); - let offset = OffsetDateTime::now_local().unwrap().offset(); - date_time - .to_offset(offset) - .format(&DATE_TIME_FORMAT) - .unwrap() + date_time.format(&DATE_TIME_FORMAT).unwrap() }) .unwrap_or_default() }) @@ -42,7 +38,7 @@ fn all_minutes(from: OffsetDateTime, to: OffsetDateTime) -> Vec { } fn valid_last_modified_template_vars(from: OffsetDateTime) -> Vec> { - all_minutes(from, OffsetDateTime::now_local().unwrap()) + all_minutes(from, OffsetDateTime::now_utc()) .into_iter() .map(|time| vec![("{last_modified_time}".to_string(), time)]) .collect() @@ -258,7 +254,7 @@ fn test_with_suppress_error_option() { fn test_with_stdin() { let expected_file_path = "stdin.log.expected"; let mut scenario = new_ucmd!(); - let start = OffsetDateTime::now_local().unwrap(); + let start = OffsetDateTime::now_utc(); scenario .pipe_in_fixture("stdin.log") .args(&["--pages=1:2", "-n", "-"]) @@ -321,7 +317,7 @@ fn test_with_mpr() { let expected_test_file_path = "mpr.log.expected"; let expected_test_file_path1 = "mpr1.log.expected"; let expected_test_file_path2 = "mpr2.log.expected"; - let start = OffsetDateTime::now_local().unwrap(); + let start = OffsetDateTime::now_utc(); new_ucmd!() .args(&["--pages=1:2", "-m", "-n", test_file_path, test_file_path1]) .succeeds() @@ -330,7 +326,7 @@ fn test_with_mpr() { &valid_last_modified_template_vars(start), ); - let start = OffsetDateTime::now_local().unwrap(); + let start = OffsetDateTime::now_utc(); new_ucmd!() .args(&["--pages=2:4", "-m", "-n", test_file_path, test_file_path1]) .succeeds() @@ -339,7 +335,7 @@ fn test_with_mpr() { &valid_last_modified_template_vars(start), ); - let start = OffsetDateTime::now_local().unwrap(); + let start = OffsetDateTime::now_utc(); new_ucmd!() .args(&[ "--pages=1:2", @@ -446,7 +442,7 @@ fn test_with_join_lines_option() { let test_file_2 = "test.log"; let expected_file_path = "joined.log.expected"; let mut scenario = new_ucmd!(); - let start = OffsetDateTime::now_local().unwrap(); + let start = OffsetDateTime::now_utc(); scenario .args(&["+1:2", "-J", "-m", test_file_1, test_file_2]) .run() diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index a0d3fd3dc..0c0a0b042 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -10,7 +10,7 @@ extern crate touch; use self::touch::filetime::{self, FileTime}; extern crate time; -use time::macros::{datetime, format_description}; +use time::macros::format_description; use crate::common::util::{AtPath, TestScenario}; use std::fs::remove_file; @@ -49,12 +49,7 @@ fn str_to_filetime(format: &str, s: &str) -> FileTime { _ => panic!("unexpected dt format"), }; let tm = time::PrimitiveDateTime::parse(s, &format_description).unwrap(); - let d = match time::OffsetDateTime::now_local() { - Ok(now) => now, - Err(e) => { - panic!("Error {e} retrieving the OffsetDateTime::now_local"); - } - }; + let d = time::OffsetDateTime::now_utc(); let offset_dt = tm.assume_offset(d.offset()); FileTime::from_unix_time(offset_dt.unix_timestamp(), tm.nanosecond()) } @@ -630,61 +625,21 @@ fn test_touch_mtime_dst_succeeds() { assert_eq!(target_time, mtime); } -// // is_dst_switch_hour returns true if timespec ts is just before the switch -// // to Daylight Saving Time. -// // For example, in EST (UTC-5), Timespec { sec: 1583647200, nsec: 0 } -// // for March 8 2020 01:00:00 AM -// // is just before the switch because on that day clock jumps by 1 hour, -// // so 1 minute after 01:59:00 is 03:00:00. -// fn is_dst_switch_hour(ts: time::Timespec) -> bool { -// let ts_after = ts + time::Duration::hours(1); -// let tm = time::at(ts); -// let tm_after = time::at(ts_after); -// tm_after.tm_hour == tm.tm_hour + 2 -// } - -// get_dst_switch_hour returns date string for which touch -m -t fails. -// For example, in EST (UTC-5), that will be "202003080200" so -// touch -m -t 202003080200 file -// fails (that date/time does not exist). -// In other locales it will be a different date/time, and in some locales -// it doesn't exist at all, in which case this function will return None. -fn get_dst_switch_hour() -> Option { - //let now = time::OffsetDateTime::now_local().unwrap(); - let now = match time::OffsetDateTime::now_local() { - Ok(now) => now, - Err(e) => { - panic!("Error {e} retrieving the OffsetDateTime::now_local"); - } - }; - - // Start from January 1, 2020, 00:00. - let tm = datetime!(2020-01-01 00:00 UTC); - tm.to_offset(now.offset()); - - // let mut ts = tm.to_timespec(); - // // Loop through all hours in year 2020 until we find the hour just - // // before the switch to DST. - // for _i in 0..(366 * 24) { - // // if is_dst_switch_hour(ts) { - // // let mut tm = time::at(ts); - // // tm.tm_hour += 1; - // // let s = time::strftime("%Y%m%d%H%M", &tm).unwrap(); - // // return Some(s); - // // } - // ts = ts + time::Duration::hours(1); - // } - None -} - #[test] +#[ignore = "not implemented"] fn test_touch_mtime_dst_fails() { let (_at, mut ucmd) = at_and_ucmd!(); let file = "test_touch_set_mtime_dst_fails"; - if let Some(s) = get_dst_switch_hour() { - ucmd.args(&["-m", "-t", &s, file]).fails(); - } + // Some timezones use daylight savings time, this leads to problems if the + // specified time is within the jump forward. In EST (UTC-5), there is a + // jump from 1:59AM to 3:00AM on, March 8 2020, so any thing in-between is + // invalid. + // See https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + // for information on the TZ variable, which where the string is copied from. + ucmd.env("TZ", "EST+5EDT,M3.2.0/2,M11.1.0/2") + .args(&["-m", "-t", "202003080200", file]) + .fails(); } #[test] diff --git a/tests/common/util.rs b/tests/common/util.rs index 3f37c7f10..586d95258 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -49,6 +49,9 @@ static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_coreutils"); pub const PATH: &str = env!("PATH"); +/// Default environment variables to run the commands with +const DEFAULT_ENV: [(&str, &str); 2] = [("LC_ALL", "C"), ("TZ", "UTC")]; + /// Test if the program is running under CI pub fn is_ci() -> bool { std::env::var("CI") @@ -1332,6 +1335,18 @@ impl UCommand { self } + pub fn envs(&mut self, iter: I) -> &mut Self + where + I: IntoIterator, + K: AsRef, + V: AsRef, + { + for (k, v) in iter { + self.env(k, v); + } + self + } + #[cfg(any(target_os = "linux", target_os = "android"))] pub fn limit( &mut self, @@ -1443,7 +1458,9 @@ impl UCommand { } } - command.envs(self.env_vars.iter().cloned()); + command + .envs(DEFAULT_ENV) + .envs(self.env_vars.iter().cloned()); if self.timeout.is_none() { self.timeout = Some(Duration::from_secs(30)); @@ -2445,7 +2462,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< let result = ts .cmd(util_name.as_ref()) .env("PATH", PATH) - .env("LC_ALL", "C") + .envs(DEFAULT_ENV) .args(args) .run(); @@ -2510,7 +2527,7 @@ pub fn run_ucmd_as_root( // check if we can run 'sudo' log_info("run", "sudo -E --non-interactive whoami"); match Command::new("sudo") - .env("LC_ALL", "C") + .envs(DEFAULT_ENV) .args(["-E", "--non-interactive", "whoami"]) .output() { @@ -2520,7 +2537,7 @@ pub fn run_ucmd_as_root( Ok(ts .cmd("sudo") .env("PATH", PATH) - .env("LC_ALL", "C") + .envs(DEFAULT_ENV) .arg("-E") .arg("--non-interactive") .arg(&ts.bin_path)