Merge pull request #8535 from yuankunzhang/who-honor-locale

who: honor locale settings
This commit is contained in:
Daniel Hofstetter 2025-09-01 17:50:48 +02:00 committed by GitHub
commit 53c4baee26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 75 additions and 6 deletions

View file

@ -163,11 +163,20 @@ fn idle_string<'a>(when: i64, boottime: i64) -> Cow<'a, str> {
}
fn time_string(ut: &UtmpxRecord) -> String {
// "%b %e %H:%M"
let time_format: Vec<time::format_description::FormatItem> =
let lc_time = std::env::var("LC_ALL")
.or_else(|_| std::env::var("LC_TIME"))
.or_else(|_| std::env::var("LANG"))
.unwrap_or_default();
let time_format: Vec<time::format_description::FormatItem> = if lc_time == "C" {
// "%b %e %H:%M"
time::format_description::parse("[month repr:short] [day padding:space] [hour]:[minute]")
.unwrap();
ut.login_time().format(&time_format).unwrap() // LC_ALL=C
.unwrap()
} else {
// "%Y-%m-%d %H:%M"
time::format_description::parse("[year]-[month]-[day] [hour]:[minute]").unwrap()
};
ut.login_time().format(&time_format).unwrap()
}
#[inline]

View file

@ -7,7 +7,7 @@
use uutests::new_ucmd;
use uutests::unwrap_or_return;
use uutests::util::{TestScenario, expected_result};
use uutests::util::{TestScenario, expected_result, gnu_cmd_result};
use uutests::util_name;
#[test]
fn test_invalid_arg() {
@ -250,3 +250,28 @@ fn test_all() {
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
}
}
#[cfg(unix)]
#[test]
#[ignore = "issue #3219"]
fn test_locale() {
let ts = TestScenario::new(util_name!());
let expected_stdout =
unwrap_or_return!(gnu_cmd_result(&ts, &[], &[("LC_ALL", "C")])).stdout_move_str();
ts.ucmd()
.env("LC_ALL", "C")
.succeeds()
.stdout_is(&expected_stdout);
let expected_stdout =
unwrap_or_return!(gnu_cmd_result(&ts, &[], &[("LC_ALL", "en_US.UTF-8")])).stdout_move_str();
ts.ucmd()
.env("LC_ALL", "C")
.succeeds()
.stdout_str_check(|s| s != expected_stdout);
ts.ucmd()
.env("LC_ALL", "en_US.UTF-8")
.succeeds()
.stdout_is(&expected_stdout);
}

View file

@ -3003,6 +3003,11 @@ fn parse_coreutil_version(version_string: &str) -> f32 {
/// If the `util_name` in `$PATH` doesn't include a coreutils version string,
/// or the version is too low, this returns an error and the test should be skipped.
///
/// Arguments:
/// - `ts`: The test context.
/// - `args`: Command-line variables applied to the command.
/// - `envs`: Environment variables applied to the command invocation.
///
/// Example:
///
/// ```no_run
@ -3019,7 +3024,11 @@ fn parse_coreutil_version(version_string: &str) -> f32 {
/// }
///```
#[cfg(unix)]
pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result<CmdResult, String> {
pub fn gnu_cmd_result(
ts: &TestScenario,
args: &[&str],
envs: &[(&str, &str)],
) -> std::result::Result<CmdResult, String> {
let util_name = ts.util_name.as_str();
println!("{}", check_coreutil_version(util_name, VERSION_MIN)?);
let util_name = host_name_for(util_name);
@ -3028,6 +3037,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result<
.cmd(util_name.as_ref())
.env("PATH", PATH)
.envs(DEFAULT_ENV)
.envs(envs.iter().copied())
.args(args)
.run();
@ -3056,6 +3066,31 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result<
))
}
/// This runs the GNU coreutils `util_name` binary in `$PATH` in order to
/// dynamically gather reference values on the system.
/// If the `util_name` in `$PATH` doesn't include a coreutils version string,
/// or the version is too low, this returns an error and the test should be skipped.
///
/// Example:
///
/// ```no_run
/// use uutests::util::*;
/// #[test]
/// fn test_xyz() {
/// let ts = TestScenario::new(util_name!());
/// let result = ts.ucmd().run();
/// let exp_result = unwrap_or_return!(expected_result(&ts, &[]));
/// result
/// .stdout_is(exp_result.stdout_str())
/// .stderr_is(exp_result.stderr_str())
/// .code_is(exp_result.code());
/// }
///```
#[cfg(unix)]
pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result<CmdResult, String> {
gnu_cmd_result(ts, args, &[])
}
/// This is a convenience wrapper to run a ucmd with root permissions.
/// It can be used to test programs when being root is needed
/// This runs `sudo -E --non-interactive target/debug/coreutils util_name args`