diff --git a/.vscode/cspell.dictionaries/jargon.wordlist.txt b/.vscode/cspell.dictionaries/jargon.wordlist.txt index 2f26340acdc..e2739d534dd 100644 --- a/.vscode/cspell.dictionaries/jargon.wordlist.txt +++ b/.vscode/cspell.dictionaries/jargon.wordlist.txt @@ -158,6 +158,7 @@ SIGTTOU sigttou sigusr strcasecmp +strtime subcommand subexpression submodule diff --git a/src/uu/date/src/locale.rs b/src/uu/date/src/locale.rs index 086b35cee58..e69c2e634dc 100644 --- a/src/uu/date/src/locale.rs +++ b/src/uu/date/src/locale.rs @@ -135,6 +135,24 @@ mod tests { cfg_langinfo! { use super::*; + /// Helper function to expand a format string with a known test date + /// + /// Uses a fixed test date: Monday, January 15, 2024, 14:30:45 UTC + /// This allows us to validate format strings by checking their expanded output + /// rather than looking for literal format codes. + fn expand_format_with_test_date(format: &str) -> String { + use jiff::civil::date; + use jiff::fmt::strtime; + + // Create test timestamp: Monday, January 15, 2024, 14:30:45 UTC + let Ok(test_date) = date(2024, 1, 15).at(14, 30, 45, 0).in_tz("UTC") else { + return String::new(); + }; + + // Expand the format string with the test date + strtime::format(format, &test_date).unwrap_or_default() + } + #[test] fn test_locale_detection() { // Just verify the function doesn't panic @@ -144,10 +162,31 @@ mod tests { #[test] fn test_default_format_contains_valid_codes() { let format = get_locale_default_format(); - assert!(format.contains("%a")); // abbreviated weekday - assert!(format.contains("%b")); // abbreviated month - assert!(format.contains("%Y") || format.contains("%y")); // year (4-digit or 2-digit) - assert!(format.contains("%Z")); // timezone + + let expanded = expand_format_with_test_date(format); + + // Verify expanded output contains expected components + // Test date: Monday, January 15, 2024, 14:30:45 + assert!( + expanded.contains("Mon") || expanded.contains("Monday"), + "Expanded format should contain weekday name, got: {expanded}" + ); + + assert!( + expanded.contains("Jan") || expanded.contains("January"), + "Expanded format should contain month name, got: {expanded}" + ); + + assert!( + expanded.contains("2024") || expanded.contains("24"), + "Expanded format should contain year, got: {expanded}" + ); + + // Keep literal %Z check - this is enforced by ensure_timezone_in_format() + assert!( + format.contains("%Z"), + "Format string must contain %Z timezone (enforced by ensure_timezone_in_format)" + ); } #[test] @@ -158,25 +197,34 @@ mod tests { // The format should not be empty assert!(!format.is_empty(), "Locale format should not be empty"); - // Should contain date/time components - let has_date_component = format.contains("%a") - || format.contains("%A") - || format.contains("%b") - || format.contains("%B") - || format.contains("%d") - || format.contains("%e"); - assert!(has_date_component, "Format should contain date components"); - - // Should contain time component (hour) - let has_time_component = format.contains("%H") - || format.contains("%I") - || format.contains("%k") - || format.contains("%l") - || format.contains("%r") - || format.contains("%R") - || format.contains("%T") - || format.contains("%X"); - assert!(has_time_component, "Format should contain time components"); + let expanded = expand_format_with_test_date(format); + + // Verify expanded output contains date components + // Test date: Monday, January 15, 2024 + let has_date_component = expanded.contains("15") // day + || expanded.contains("Jan") // month name + || expanded.contains("January") // full month + || expanded.contains("Mon") // weekday + || expanded.contains("Monday"); // full weekday + + assert!( + has_date_component, + "Expanded format should contain date components, got: {expanded}" + ); + + // Verify expanded output contains time components + // Test time: 14:30:45 + let has_time_component = expanded.contains("14") // 24-hour + || expanded.contains("02") // 12-hour + || expanded.contains("30") // minutes + || expanded.contains(':') // time separator + || expanded.contains("PM") // AM/PM indicator + || expanded.contains("pm"); + + assert!( + has_time_component, + "Expanded format should contain time components, got: {expanded}" + ); } #[test]